|
|
<?php |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace think\cache; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
abstract class Driver |
|
|
{ |
|
|
protected $handler = null; |
|
|
protected $options = []; |
|
|
protected $tag; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
abstract public function has($name); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
abstract public function get($name, $default = false); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
abstract public function set($name, $value, $expire = null); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
abstract public function inc($name, $step = 1); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
abstract public function dec($name, $step = 1); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
abstract public function rm($name); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
abstract public function clear($tag = null); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected function getCacheKey($name) |
|
|
{ |
|
|
return $this->options['prefix'] . $name; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function pull($name) |
|
|
{ |
|
|
$result = $this->get($name, false); |
|
|
if ($result) { |
|
|
$this->rm($name); |
|
|
return $result; |
|
|
} else { |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function remember($name, $value, $expire = null) |
|
|
{ |
|
|
if (!$this->has($name)) { |
|
|
$time = time(); |
|
|
while ($time + 5 > time() && $this->has($name . '_lock')) { |
|
|
|
|
|
usleep(200000); |
|
|
} |
|
|
|
|
|
try { |
|
|
|
|
|
$this->set($name . '_lock', true); |
|
|
if ($value instanceof \Closure) { |
|
|
$value = call_user_func($value); |
|
|
} |
|
|
$this->set($name, $value, $expire); |
|
|
|
|
|
$this->rm($name . '_lock'); |
|
|
} catch (\Exception $e) { |
|
|
|
|
|
$this->rm($name . '_lock'); |
|
|
throw $e; |
|
|
} catch (\throwable $e) { |
|
|
$this->rm($name . '_lock'); |
|
|
throw $e; |
|
|
} |
|
|
} else { |
|
|
$value = $this->get($name); |
|
|
} |
|
|
return $value; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function tag($name, $keys = null, $overlay = false) |
|
|
{ |
|
|
if (is_null($name)) { |
|
|
|
|
|
} elseif (is_null($keys)) { |
|
|
$this->tag = $name; |
|
|
} else { |
|
|
$key = 'tag_' . md5($name); |
|
|
if (is_string($keys)) { |
|
|
$keys = explode(',', $keys); |
|
|
} |
|
|
$keys = array_map([$this, 'getCacheKey'], $keys); |
|
|
if ($overlay) { |
|
|
$value = $keys; |
|
|
} else { |
|
|
$value = array_unique(array_merge($this->getTagItem($name), $keys)); |
|
|
} |
|
|
$this->set($key, implode(',', $value), 0); |
|
|
} |
|
|
return $this; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected function setTagItem($name) |
|
|
{ |
|
|
if ($this->tag) { |
|
|
$key = 'tag_' . md5($this->tag); |
|
|
$this->tag = null; |
|
|
if ($this->has($key)) { |
|
|
$value = explode(',', $this->get($key)); |
|
|
$value[] = $name; |
|
|
$value = implode(',', array_unique($value)); |
|
|
} else { |
|
|
$value = $name; |
|
|
} |
|
|
$this->set($key, $value, 0); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected function getTagItem($tag) |
|
|
{ |
|
|
$key = 'tag_' . md5($tag); |
|
|
$value = $this->get($key); |
|
|
if ($value) { |
|
|
return array_filter(explode(',', $value)); |
|
|
} else { |
|
|
return []; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function handler() |
|
|
{ |
|
|
return $this->handler; |
|
|
} |
|
|
} |
|
|
|