这个问题类似于一个关于java的问题,但我在php中这样做,所以我不认为它有资格作为重复.
我想要一种在调用此函数时生成确定性键的方法.该函数应该像读取缓存一样运行.如果密钥存在,则检索数据.如果没有,调用函数存储数据,然后返回它.
这是我拥有的,它的工作原理,但我不确定它是否安全,如果它的确定性足够甚至足够独特,因为我对这些主题完全没有理解.
// $call = function being called $args = arguments to that function
// $force = force cache to bypassed, then updated
public function cachedCall($call,$args = [],$force = false)
{
$cache = \App\App::getInstance()->cache;
$key = md5($call) . md5(serialize($args));
$res = $cache->get($key);
if($res === -1 || $force){
$res = call_user_func_array([$this,$call],$args);
if(!empty($res) && $res !== false && $res !== 0 && !is_null($res)){
$cache->set($key,$res,0); //never set empty data in the cache.
}
}
return $res;
}
Run Code Online (Sandbox Code Playgroud)
我的问题只涉及计算密钥的第三行.你可以看到它是由被调用的函数和要提供给该函数的参数计算的.我在某些情况下发生了碰撞.我正在寻找改进它的方法,因此它更有用,哈希是一致的但不太可能发生冲突.第三个参数可以忽略,因为它只是一种强制缓存被绕过的方法.
如何调用此函数的示例:
$data = $db->cachedCall('getUserByEmail',[$this->email],true);
$data = $db->cachedCall('getCell',['SELECT id FROM foobar WHERE foo=:bar',[':bar'=>55]]);
如果可能的话,我想保证密钥同时具有一致的长度.
这是因为键在不同实例中可能是相同的,例如当调用方法cachedCall时具有相同的参数。正如我想象的那样,您应该为每个实例共享相同的memcached服务器,这就是缓存冲突的原因。
正如我所读到的,变量$call将具有与代码的任何其他部分共享的有限值,因为它将包含包含方法cachedCall的类的方法名称,这意味着两个不同的值很容易看涨期权分享这个价值。
此外,您可以使用空参数数组调用此方法。
因此,在两个不同的实例中调用相同的方法是很容易的:
cachedCall('methodX', array()); <- From instance A
cachedCall('methodX', array()); <- From instance B
Run Code Online (Sandbox Code Playgroud)
这会将此内容存储在同一个memcached 键中
在方法内部,以某种方式考虑实例名称。例如,您可以使用当前 url 作为密钥或域名的一部分(取决于您的情况):
$key = md5($call) . md5(serialize($args)) . md5($_SERVER['HTTP_HOST']);
$key = md5($call) . md5(serialize($args)) . md5($_SERVER['REQUEST_URI']);
Run Code Online (Sandbox Code Playgroud)
在上面您可以看到两个示例,说明如何根据您的实例更改memcached 键。