/crmeb/vendor/topthink/framework/src/think/cache/Driver.php

https://github.com/crmeb/CRMEB · PHP · 346 lines · 158 code · 50 blank · 138 comment · 13 complexity · 340cd475ff57980682c9fa987906a5f6 MD5 · raw file

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