Completed
Pull Request — 6.0 (#2187)
by topphp
08:15
created

Driver::setMultiple()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 5
c 1
b 0
f 0
nc 3
nop 2
dl 0
loc 11
ccs 6
cts 6
cp 1
crap 3
rs 10
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 <[email protected]>
10
// +----------------------------------------------------------------------
11
declare (strict_types = 1);
12
13
namespace think\cache;
14
15
use Closure;
16
use DateInterval;
17
use DateTime;
18
use DateTimeInterface;
19
use Exception;
20
use Psr\SimpleCache\CacheInterface;
21
use think\Container;
22
use think\contract\CacheHandlerInterface;
23
use think\exception\InvalidArgumentException;
24
use throwable;
25
26
/**
27
 * 缓存基础类
28
 */
29
abstract class Driver implements CacheInterface, CacheHandlerInterface
30
{
31
    /**
32
     * 驱动句柄
33
     * @var object
34
     */
35
    protected $handler = null;
36
37
    /**
38
     * 缓存读取次数
39
     * @var integer
40
     */
41
    protected $readTimes = 0;
42
43
    /**
44
     * 缓存写入次数
45
     * @var integer
46
     */
47
    protected $writeTimes = 0;
48
49
    /**
50
     * 缓存参数
51
     * @var array
52
     */
53
    protected $options = [];
54
55
    /**
56
     * 缓存标签
57
     * @var array
58
     */
59
    protected $tag = [];
60
61
    /**
62
     * 获取有效期
63
     * @access protected
64
     * @param integer|DateTimeInterface|DateInterval $expire 有效期
65
     * @return int
66
     */
67 1
    protected function getExpireTime($expire): int
68
    {
69 1
        if ($expire instanceof DateTimeInterface) {
70
            $expire = $expire->getTimestamp() - time();
71 1
        } elseif ($expire instanceof DateInterval) {
72
            $expire = DateTime::createFromFormat('U', (string) time())
73
                ->add($expire)
74
                ->format('U') - time();
75
        }
76
77 1
        return (int) $expire;
78
    }
79
80
    /**
81
     * 获取实际的缓存标识
82
     * @access public
83
     * @param string $name 缓存名
84
     * @return string
85
     */
86
    public function getCacheKey(string $name): string
87
    {
88
        return $this->options['prefix'] . $name;
89
    }
90
91
    /**
92
     * 读取缓存并删除
93
     * @access public
94
     * @param string $name 缓存变量名
95
     * @return mixed
96
     */
97
    public function pull(string $name)
98
    {
99
        $result = $this->get($name, false);
100
101
        if ($result) {
102
            $this->delete($name);
103
            return $result;
104
        }
105
    }
106
107
    /**
108
     * 追加(数组)缓存
109
     * @access public
110
     * @param string $name  缓存变量名
111
     * @param mixed  $value 存储数据
112
     * @return void
113
     */
114 1
    public function push(string $name, $value): void
115
    {
116 1
        $item = $this->get($name, []);
117
118 1
        if (!is_array($item)) {
119
            throw new InvalidArgumentException('only array cache can be push');
120
        }
121
122 1
        $item[] = $value;
123
124 1
        if (count($item) > 1000) {
125
            array_shift($item);
126
        }
127
128 1
        $item = array_unique($item);
129
130 1
        $this->set($name, $item);
131 1
    }
132
133
    /**
134
     * 如果不存在则写入缓存
135
     * @access public
136
     * @param string $name   缓存变量名
137
     * @param mixed  $value  存储数据
138
     * @param int    $expire 有效时间 0为永久
139
     * @return mixed
140
     */
141
    public function remember(string $name, $value, $expire = null)
142
    {
143
        if ($this->has($name)) {
144
            return $this->get($name);
145
        }
146
147
        $time = time();
148
149
        while ($time + 5 > time() && $this->has($name . '_lock')) {
150
            // 存在锁定则等待
151
            usleep(200000);
152
        }
153
154
        try {
155
            // 锁定
156
            $this->set($name . '_lock', true);
157
158
            if ($value instanceof Closure) {
159
                // 获取缓存数据
160
                $value = Container::getInstance()->invokeFunction($value);
161
            }
162
163
            // 缓存数据
164
            $this->set($name, $value, $expire);
165
166
            // 解锁
167
            $this->delete($name . '_lock');
168
        } catch (Exception | throwable $e) {
169
            $this->delete($name . '_lock');
170
            throw $e;
171
        }
172
173
        return $value;
174
    }
175
176
    /**
177
     * 缓存标签
178
     * @access public
179
     * @param string|array $name 标签名
180
     * @return TagSet
181
     */
182 1
    public function tag($name): TagSet
183
    {
184 1
        $name = (array) $name;
185 1
        $key  = implode('-', $name);
186
187 1
        if (!isset($this->tag[$key])) {
188
            $name = array_map(function ($val) {
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
189 1
                return $this->getTagKey($val);
190 1
            }, $name);
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
191 1
            $this->tag[$key] = new TagSet($name, $this);
192
        }
193
194 1
        return $this->tag[$key];
195
    }
196
197
    /**
198
     * 获取标签包含的缓存标识
199
     * @access public
200
     * @param string $tag 标签标识
201
     * @return array
202
     */
203 1
    public function getTagItems(string $tag): array
204
    {
205 1
        return $this->get($tag, []);
206
    }
207
208
    /**
209
     * 获取实际标签名
210
     * @access public
211
     * @param string $tag 标签名
212
     * @return string
213
     */
214 1
    public function getTagKey(string $tag): string
215
    {
216 1
        return $this->options['tag_prefix'] . md5($tag);
217
    }
218
219
    /**
220
     * 序列化数据
221
     * @access protected
222
     * @param mixed $data 缓存数据
223
     * @return string
224
     */
225 1
    protected function serialize($data): string
226
    {
227 1
        if (is_numeric($data)) {
228 1
            return (string) $data;
229
        }
230
231 1
        $serialize = $this->options['serialize'][0] ?? "serialize";
232
233 1
        return $serialize($data);
234
    }
235
236
    /**
237
     * 反序列化数据
238
     * @access protected
239
     * @param string $data 缓存数据
240
     * @return mixed
241
     */
242 1
    protected function unserialize(string $data)
243
    {
244 1
        if (is_numeric($data)) {
245 1
            return $data;
246
        }
247
248 1
        $unserialize = $this->options['serialize'][1] ?? "unserialize";
249
250 1
        return $unserialize($data);
251
    }
252
253
    /**
254
     * 返回句柄对象,可执行其它高级方法
255
     *
256
     * @access public
257
     * @return object
258
     */
259
    public function handler()
260
    {
261
        return $this->handler;
262
    }
263
264
    /**
265
     * 返回缓存读取次数
266
     * @access public
267
     * @return int
268
     */
269
    public function getReadTimes(): int
270
    {
271
        return $this->readTimes;
272
    }
273
274
    /**
275
     * 返回缓存写入次数
276
     * @access public
277
     * @return int
278
     */
279
    public function getWriteTimes(): int
280
    {
281
        return $this->writeTimes;
282
    }
283
284
    /**
285
     * 读取缓存
286
     * @access public
287
     * @param iterable $keys    缓存变量名
288
     * @param mixed    $default 默认值
289
     * @return iterable
290
     * @throws InvalidArgumentException
291
     */
292 1
    public function getMultiple($keys, $default = null): iterable
293
    {
294 1
        $result = [];
295
296 1
        foreach ($keys as $key) {
297 1
            $result[$key] = $this->get($key, $default);
298
        }
299
300 1
        return $result;
301
    }
302
303
    /**
304
     * 写入缓存
305
     * @access public
306
     * @param iterable               $values 缓存数据
307
     * @param null|int|\DateInterval $ttl    有效时间 0为永久
308
     * @return bool
309
     */
310 1
    public function setMultiple($values, $ttl = null): bool
311
    {
312 1
        foreach ($values as $key => $val) {
313 1
            $result = $this->set($key, $val, $ttl);
314
315 1
            if (false === $result) {
316 1
                return false;
317
            }
318
        }
319
320 1
        return true;
321
    }
322
323
    /**
324
     * 删除缓存
325
     * @access public
326
     * @param iterable $keys 缓存变量名
327
     * @return bool
328
     * @throws InvalidArgumentException
329
     */
330 1
    public function deleteMultiple($keys): bool
331
    {
332 1
        foreach ($keys as $key) {
333 1
            $result = $this->delete($key);
334
335 1
            if (false === $result) {
336 1
                return false;
337
            }
338
        }
339
340 1
        return true;
341
    }
342
343
    public function __call($method, $args)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function __call()
Loading history...
344
    {
345
        return call_user_func_array([$this->handler, $method], $args);
346
    }
347
}
348