Completed
Push — 6.0 ( 9dcf40...bc5730 )
by liu
19:01 queued 05:06
created

Driver::push()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 7
nc 2
nop 3
dl 0
loc 13
ccs 0
cts 8
cp 0
crap 6
rs 10
c 0
b 0
f 0
1
<?php
2
// +----------------------------------------------------------------------
1 ignored issue
show
Coding Style introduced by
You must use "/**" style comments for a file comment
Loading history...
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 think\Container;
16
use think\exception\InvalidArgumentException;
17
18
/**
19
 * 缓存基础类
20
 */
5 ignored issues
show
Coding Style introduced by
Missing @category tag in class comment
Loading history...
Coding Style introduced by
Missing @package tag in class comment
Loading history...
Coding Style introduced by
Missing @author tag in class comment
Loading history...
Coding Style introduced by
Missing @license tag in class comment
Loading history...
Coding Style introduced by
Missing @link tag in class comment
Loading history...
21
abstract class Driver extends SimpleCache
22
{
23
    /**
24
     * 驱动句柄
25
     * @var object
26
     */
27
    protected $handler = null;
28
29
    /**
30
     * 缓存读取次数
31
     * @var integer
32
     */
33
    protected $readTimes = 0;
34
35
    /**
36
     * 缓存写入次数
37
     * @var integer
38
     */
39
    protected $writeTimes = 0;
40
41
    /**
42
     * 缓存参数
43
     * @var array
44
     */
45
    protected $options = [];
46
47
    /**
48
     * 缓存标签
49
     * @var array
50
     */
51
    protected $tag;
52
53
    /**
54
     * 获取有效期
55
     * @access protected
56
     * @param  integer|\DateTimeInterface $expire 有效期
57
     * @return int
58
     */
59
    protected function getExpireTime($expire): int
60
    {
61
        if ($expire instanceof \DateTimeInterface) {
62
            $expire = $expire->getTimestamp() - time();
63
        }
64
65
        return (int) $expire;
66
    }
67
68
    /**
69
     * 获取实际的缓存标识
70
     * @access protected
71
     * @param  string $name 缓存名
72
     * @return string
73
     */
74
    protected function getCacheKey(string $name): string
75
    {
76
        return $this->options['prefix'] . $name;
77
    }
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
89
        if ($result) {
90
            $this->rm($name);
91
            return $result;
92
        }
93
    }
94
95
    /**
96
     * 追加(数组)缓存
97
     * @access public
98
     * @param  string        $name 缓存变量名
0 ignored issues
show
Coding Style introduced by
Expected 3 spaces after parameter name; 1 found
Loading history...
99
     * @param  mixed         $value  存储数据
100
     * @param  int|\DateTime $expire  有效时间 0为永久
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
101
     * @return array
102
     */
103
    public function push($name, $value, $expire = null): array
104
    {
105
        $item = $this->get($name, []);
106
107
        if (!is_array($item)) {
108
            throw new InvalidArgumentException('only array cache can be push');
109
        }
110
111
        $item[] = $value;
112
        $item   = array_unique($item);
113
114
        $this->set($name, $item, $expire);
0 ignored issues
show
Bug introduced by
It seems like $expire can also be of type DateTime; however, parameter $expire of think\cache\SimpleCache::set() does only seem to accept DateInterval|integer|null, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

114
        $this->set($name, $item, /** @scrutinizer ignore-type */ $expire);
Loading history...
115
        return $item;
116
    }
117
118
    /**
119
     * 如果不存在则写入缓存
120
     * @access public
121
     * @param  string $name 缓存变量名
0 ignored issues
show
Coding Style introduced by
Expected 3 spaces after parameter name; 1 found
Loading history...
122
     * @param  mixed  $value  存储数据
123
     * @param  int    $expire  有效时间 0为永久
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
124
     * @return mixed
125
     */
126
    public function remember(string $name, $value, $expire = null)
127
    {
128
        if ($this->has($name)) {
129
            return $this->get($name);
130
        }
131
132
        $time = time();
133
134
        while ($time + 5 > time() && $this->has($name . '_lock')) {
135
            // 存在锁定则等待
136
            usleep(200000);
137
        }
138
139
        try {
140
            // 锁定
141
            $this->set($name . '_lock', true);
142
143
            if ($value instanceof \Closure) {
144
                // 获取缓存数据
145
                $value = Container::getInstance()->invokeFunction($value);
146
            }
147
148
            // 缓存数据
149
            $this->set($name, $value, $expire);
150
151
            // 解锁
152
            $this->rm($name . '_lock');
153
        } catch (\Exception | \throwable $e) {
154
            $this->rm($name . '_lock');
155
            throw $e;
156
        }
157
158
        return $value;
159
    }
160
161
    /**
162
     * 缓存标签
163
     * @access public
164
     * @param  string|array $name 标签名
165
     * @return $this
166
     */
167
    public function tag($name)
168
    {
169
        if ($name) {
170
            $this->tag = (array) $name;
171
        }
172
173
        return $this;
174
    }
175
176
    /**
177
     * 更新标签
178
     * @access protected
179
     * @param  string $name 缓存标识
180
     * @return void
181
     */
182
    protected function setTagItem(string $name): void
183
    {
184
        if (!empty($this->tag)) {
185
            $tags      = $this->tag;
186
            $this->tag = null;
187
188
            foreach ($tags as $tag) {
189
                $value   = $this->getTagItems($tag);
190
                $value[] = $name;
191
192
                if (count($value) > 1000) {
193
                    array_shift($value);
194
                }
195
196
                $value = array_unique($value);
197
198
                $this->set($key, $value, 0);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $key seems to be never defined.
Loading history...
199
            }
200
        }
201
    }
202
203
    /**
204
     * 获取标签包含的缓存标识
205
     * @access protected
206
     * @param  string $tag 缓存标签
207
     * @return array
208
     */
209
    protected function getTagItems(string $tag): array
210
    {
211
        $key = $this->getTagkey($tag);
212
        return $this->get($key, []);
213
    }
214
215
    /**
216
     * 获取实际标签名
217
     * @access protected
218
     * @param  string $tag 标签名
219
     * @return string
220
     */
221
    protected function getTagKey(string $tag): string
222
    {
223
        return $this->options['tag_prefix'] . md5($tag);
224
    }
225
226
    /**
227
     * 序列化数据
228
     * @access protected
229
     * @param  mixed $data 缓存数据
230
     * @return string
231
     */
232
    protected function serialize($data): string
233
    {
234
        $serialize = $this->options['serialize'][0] ?? '\think\App::serialize';
235
236
        return $serialize($data);
237
    }
238
239
    /**
240
     * 反序列化数据
241
     * @access protected
242
     * @param  string $data 缓存数据
243
     * @return mixed
244
     */
245
    protected function unserialize(string $data)
246
    {
247
        $unserialize = $this->options['serialize'][1] ?? '\think\App::unserialize';
248
249
        return $unserialize($data);
250
    }
251
252
    /**
253
     * 返回句柄对象,可执行其它高级方法
254
     *
255
     * @access public
256
     * @return object
257
     */
258
    public function handler()
259
    {
260
        return $this->handler;
261
    }
262
263
    /**
264
     * 返回缓存读取次数
265
     * @access public
266
     * @return int
267
     */
268
    public function getReadTimes(): int
269
    {
270
        return $this->readTimes;
271
    }
272
273
    /**
274
     * 返回缓存写入次数
275
     * @access public
276
     * @return int
277
     */
278
    public function getWriteTimes(): int
279
    {
280
        return $this->writeTimes;
281
    }
282
283
    public function __call($method, $args)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function __call()
Loading history...
284
    {
285
        return call_user_func_array([$this->handler, $method], $args);
286
    }
287
}
288