另一种方法(我没有尝试过,但听起来很有趣)是利用 opcache 作为键值缓存。这篇 graphiq 帖子包含更多细节,但遗憾的是没有真正的代码(请注意来自 Kerry Schwab 的 cmets)。
它的要点是确保 opcache 已启用并为您需要缓存的数据分配足够的内存,然后按照以下内容进行操作(摘自文章,完整查看)。缓存过期(除了手动删除)也需要处理,但不会很难添加(例如,将您的数据包装在具有过期时间的包含对象中并在您的cache_get 中检查它,删除并忽略记录如果它已过期)。
function cache_set($key, $val) {
$val = var_export($val, true);
// HHVM fails at __set_state, so just use object cast for now
$val = str_replace('stdClass::__set_state', '(object)', $val);
// Write to temp file first to ensure atomicity
$tmp = "/tmp/$key." . uniqid('', true) . '.tmp';
file_put_contents($tmp, '<?php $val = ' . $val . ';', LOCK_EX);
rename($tmp, "/tmp/$key");
}
function cache_get($key) {
@include "/tmp/$key";
return isset($val) ? $val : false;
}
由于 opcache 的作用是作为内存中的缓存,但它避免了序列化和反序列化的开销。我猜 cache_set 在写入时也应该调用opcache_invalidate(以及在他们的示例中不存在的cache_delete 函数中),但是对于不需要在服务器之间共享的缓存来说似乎是合理的。
编辑:缓存到期的示例实现(仅精确到一秒,如果需要更高的精确度,可以使用microtime(true))。实际上做了最少的测试,我放弃了 HHVM 特定的替换,所以 YMMV。欢迎提出改进建议。
class Cache {
private $root;
private $compile;
private $ttl;
public function __construct($options = []) {
$this->options = array_merge(
array(
'root' => sys_get_temp_dir(),
'ttl' => false,
),
$options
);
$this->root = $this->options['root'];
$this->ttl = $this->options['ttl'];
}
public function set($key, $val, $ttl = null) {
$ttl = $ttl === null ? $this->ttl : $ttl;
$file = md5($key);
$val = var_export(array(
'expiry' => $ttl ? time() + $ttl : false,
'data' => $val,
), true);
// Write to temp file first to ensure atomicity
$tmp = $this->root . '/' . $file . '.' . uniqid('', true) . '.tmp';
file_put_contents($tmp, '<?php $val = ' . $val . ';', LOCK_EX);
$dest = $this->root . '/' . $file;
rename($tmp, $dest);
opcache_invalidate($dest);
}
public function get($key) {
@include $this->root . '/' . md5($key);
// Not found
if (!isset($val)) return null;
// Found and not expired
if (!$val['expiry'] || $val['expiry'] > time()) return $val['data'];
// Expired, clean up
$this->remove($key);
}
public function remove($key) {
$dest = $this->root . '/' . md5($key);
if (@unlink($dest)) {
// Invalidate cache if successfully written
opcache_invalidate($dest);
}
}
}