Driver.php 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | ThinkPHP [ WE CAN DO IT JUST THINK ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8. // +----------------------------------------------------------------------
  9. // | Author: liu21st <liu21st@gmail.com>
  10. // +----------------------------------------------------------------------
  11. declare (strict_types = 1);
  12. namespace think\cache;
  13. use DateInterval;
  14. use DateTime;
  15. use DateTimeInterface;
  16. use Opis\Closure\SerializableClosure;
  17. use Psr\SimpleCache\CacheInterface;
  18. use think\cache\exception\InvalidArgumentException;
  19. use think\Container;
  20. /**
  21. * 缓存基础类
  22. */
  23. abstract class Driver implements CacheInterface
  24. {
  25. /**
  26. * 驱动句柄
  27. * @var object
  28. */
  29. protected $handler = null;
  30. /**
  31. * 缓存读取次数
  32. * @var integer
  33. */
  34. protected $readTimes = 0;
  35. /**
  36. * 缓存写入次数
  37. * @var integer
  38. */
  39. protected $writeTimes = 0;
  40. /**
  41. * 缓存参数
  42. * @var array
  43. */
  44. protected $options = [];
  45. /**
  46. * 缓存标签
  47. * @var array
  48. */
  49. protected $tag = [];
  50. /**
  51. * 获取有效期
  52. * @access protected
  53. * @param integer|DateTimeInterface|DateInterval $expire 有效期
  54. * @return int
  55. */
  56. protected function getExpireTime($expire): int
  57. {
  58. if ($expire instanceof DateTimeInterface) {
  59. $expire = $expire->getTimestamp() - time();
  60. } elseif ($expire instanceof DateInterval) {
  61. $expire = DateTime::createFromFormat('U', (string) time())
  62. ->add($expire)
  63. ->format('U') - time();
  64. }
  65. return (int) $expire;
  66. }
  67. /**
  68. * 获取实际的缓存标识
  69. * @access public
  70. * @param string $name 缓存名
  71. * @return string
  72. */
  73. public function getCacheKey(string $name): string
  74. {
  75. return $this->options['prefix'] . $name;
  76. }
  77. /**
  78. * 读取缓存并删除
  79. * @access public
  80. * @param string $name 缓存变量名
  81. * @return mixed
  82. */
  83. public function pull(string $name)
  84. {
  85. $result = $this->get($name, false);
  86. if ($result) {
  87. $this->delete($name);
  88. return $result;
  89. }
  90. }
  91. /**
  92. * 追加(数组)缓存
  93. * @access public
  94. * @param string $name 缓存变量名
  95. * @param mixed $value 存储数据
  96. * @return void
  97. */
  98. public function push(string $name, $value): void
  99. {
  100. $item = $this->get($name, []);
  101. if (!is_array($item)) {
  102. throw new InvalidArgumentException('only array cache can be push');
  103. }
  104. $item[] = $value;
  105. if (count($item) > 1000) {
  106. array_shift($item);
  107. }
  108. $item = array_unique($item);
  109. $this->set($name, $item);
  110. }
  111. /**
  112. * 如果不存在则写入缓存
  113. * @access public
  114. * @param string $name 缓存变量名
  115. * @param mixed $value 存储数据
  116. * @param int $expire 有效时间 0为永久
  117. * @return mixed
  118. */
  119. public function remember(string $name, $value, $expire = null)
  120. {
  121. if ($this->has($name)) {
  122. return $this->get($name);
  123. }
  124. $time = time();
  125. while ($time + 5 > time() && $this->has($name . '_lock')) {
  126. // 存在锁定则等待
  127. usleep(200000);
  128. }
  129. try {
  130. // 锁定
  131. $this->set($name . '_lock', true);
  132. if ($value instanceof \Closure) {
  133. // 获取缓存数据
  134. $value = Container::getInstance()->invokeFunction($value);
  135. }
  136. // 缓存数据
  137. $this->set($name, $value, $expire);
  138. // 解锁
  139. $this->delete($name . '_lock');
  140. } catch (\Exception | \throwable $e) {
  141. $this->delete($name . '_lock');
  142. throw $e;
  143. }
  144. return $value;
  145. }
  146. /**
  147. * 缓存标签
  148. * @access public
  149. * @param string|array $name 标签名
  150. * @return $this
  151. */
  152. public function tag($name)
  153. {
  154. $name = (array) $name;
  155. $key = implode('-', $name);
  156. if (!isset($this->tag[$key])) {
  157. $name = array_map(function ($val) {
  158. return $this->getTagKey($val);
  159. }, $name);
  160. $this->tag[$key] = new TagSet($name, $this);
  161. }
  162. return $this->tag[$key];
  163. }
  164. /**
  165. * 获取标签包含的缓存标识
  166. * @access public
  167. * @param string $tag 标签标识
  168. * @return array
  169. */
  170. public function getTagItems(string $tag): array
  171. {
  172. $name = $this->getTagKey($tag);
  173. return $this->get($name, []);
  174. }
  175. /**
  176. * 获取实际标签名
  177. * @access public
  178. * @param string $tag 标签名
  179. * @return string
  180. */
  181. public function getTagKey(string $tag): string
  182. {
  183. return $this->options['tag_prefix'] . md5($tag);
  184. }
  185. /**
  186. * 序列化数据
  187. * @access protected
  188. * @param mixed $data 缓存数据
  189. * @return string
  190. */
  191. protected function serialize($data): string
  192. {
  193. $serialize = $this->options['serialize'][0] ?? function ($data) {
  194. SerializableClosure::enterContext();
  195. SerializableClosure::wrapClosures($data);
  196. $data = \serialize($data);
  197. SerializableClosure::exitContext();
  198. return $data;
  199. };
  200. return $serialize($data);
  201. }
  202. /**
  203. * 反序列化数据
  204. * @access protected
  205. * @param string $data 缓存数据
  206. * @return mixed
  207. */
  208. protected function unserialize(string $data)
  209. {
  210. $unserialize = $this->options['serialize'][1] ?? function ($data) {
  211. SerializableClosure::enterContext();
  212. $data = \unserialize($data);
  213. SerializableClosure::unwrapClosures($data);
  214. SerializableClosure::exitContext();
  215. return $data;
  216. };
  217. return $unserialize($data);
  218. }
  219. /**
  220. * 返回句柄对象,可执行其它高级方法
  221. *
  222. * @access public
  223. * @return object
  224. */
  225. public function handler()
  226. {
  227. return $this->handler;
  228. }
  229. /**
  230. * 返回缓存读取次数
  231. * @access public
  232. * @return int
  233. */
  234. public function getReadTimes(): int
  235. {
  236. return $this->readTimes;
  237. }
  238. /**
  239. * 返回缓存写入次数
  240. * @access public
  241. * @return int
  242. */
  243. public function getWriteTimes(): int
  244. {
  245. return $this->writeTimes;
  246. }
  247. /**
  248. * 读取缓存
  249. * @access public
  250. * @param iterable $keys 缓存变量名
  251. * @param mixed $default 默认值
  252. * @return iterable
  253. * @throws InvalidArgumentException
  254. */
  255. public function getMultiple($keys, $default = null): iterable
  256. {
  257. $result = [];
  258. foreach ($keys as $key) {
  259. $result[$key] = $this->get($key, $default);
  260. }
  261. return $result;
  262. }
  263. /**
  264. * 写入缓存
  265. * @access public
  266. * @param iterable $values 缓存数据
  267. * @param null|int|\DateInterval $ttl 有效时间 0为永久
  268. * @return bool
  269. */
  270. public function setMultiple($values, $ttl = null): bool
  271. {
  272. foreach ($values as $key => $val) {
  273. $result = $this->set($key, $val, $ttl);
  274. if (false === $result) {
  275. return false;
  276. }
  277. }
  278. return true;
  279. }
  280. /**
  281. * 删除缓存
  282. * @access public
  283. * @param iterable $keys 缓存变量名
  284. * @return bool
  285. * @throws InvalidArgumentException
  286. */
  287. public function deleteMultiple($keys): bool
  288. {
  289. foreach ($keys as $key) {
  290. $result = $this->delete($key);
  291. if (false === $result) {
  292. return false;
  293. }
  294. }
  295. return true;
  296. }
  297. public function __call($method, $args)
  298. {
  299. return call_user_func_array([$this->handler, $method], $args);
  300. }
  301. }