1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* @link http://www.yiiframework.com/ |
4
|
|
|
* @copyright Copyright (c) 2008 Yii Software LLC |
5
|
|
|
* @license http://www.yiiframework.com/license/ |
6
|
|
|
*/ |
7
|
|
|
|
8
|
|
|
namespace yii\caching; |
9
|
|
|
|
10
|
|
|
use Yii; |
11
|
|
|
use yii\base\InvalidConfigException; |
12
|
|
|
|
13
|
|
|
/** |
14
|
|
|
* MemCache implements a cache application component based on [memcache](http://pecl.php.net/package/memcache) |
15
|
|
|
* and [memcached](http://pecl.php.net/package/memcached). |
16
|
|
|
* |
17
|
|
|
* MemCache supports both [memcache](http://pecl.php.net/package/memcache) and |
18
|
|
|
* [memcached](http://pecl.php.net/package/memcached). By setting [[useMemcached]] to be true or false, |
19
|
|
|
* one can let MemCache to use either memcached or memcache, respectively. |
20
|
|
|
* |
21
|
|
|
* MemCache can be configured with a list of memcache servers by settings its [[servers]] property. |
22
|
|
|
* By default, MemCache assumes there is a memcache server running on localhost at port 11211. |
23
|
|
|
* |
24
|
|
|
* See [[Cache]] for common cache operations that MemCache supports. |
25
|
|
|
* |
26
|
|
|
* Note, there is no security measure to protected data in memcache. |
27
|
|
|
* All data in memcache can be accessed by any process running in the system. |
28
|
|
|
* |
29
|
|
|
* To use MemCache as the cache application component, configure the application as follows, |
30
|
|
|
* |
31
|
|
|
* ```php |
32
|
|
|
* [ |
33
|
|
|
* 'components' => [ |
34
|
|
|
* 'cache' => [ |
35
|
|
|
* 'class' => 'yii\caching\MemCache', |
36
|
|
|
* 'servers' => [ |
37
|
|
|
* [ |
38
|
|
|
* 'host' => 'server1', |
39
|
|
|
* 'port' => 11211, |
40
|
|
|
* 'weight' => 60, |
41
|
|
|
* ], |
42
|
|
|
* [ |
43
|
|
|
* 'host' => 'server2', |
44
|
|
|
* 'port' => 11211, |
45
|
|
|
* 'weight' => 40, |
46
|
|
|
* ], |
47
|
|
|
* ], |
48
|
|
|
* ], |
49
|
|
|
* ], |
50
|
|
|
* ] |
51
|
|
|
* ``` |
52
|
|
|
* |
53
|
|
|
* In the above, two memcache servers are used: server1 and server2. You can configure more properties of |
54
|
|
|
* each server, such as `persistent`, `weight`, `timeout`. Please see [[MemCacheServer]] for available options. |
55
|
|
|
* |
56
|
|
|
* For more details and usage information on Cache, see the [guide article on caching](guide:caching-overview). |
57
|
|
|
* |
58
|
|
|
* @property \Memcache|\Memcached $memcache The memcache (or memcached) object used by this cache component. |
59
|
|
|
* This property is read-only. |
60
|
|
|
* @property MemCacheServer[] $servers List of memcache server configurations. Note that the type of this |
61
|
|
|
* property differs in getter and setter. See [[getServers()]] and [[setServers()]] for details. |
62
|
|
|
* |
63
|
|
|
* @author Qiang Xue <[email protected]> |
64
|
|
|
* @since 2.0 |
65
|
|
|
*/ |
66
|
|
|
class MemCache extends Cache |
67
|
|
|
{ |
68
|
|
|
/** |
69
|
|
|
* @var bool whether to use memcached or memcache as the underlying caching extension. |
70
|
|
|
* If true, [memcached](http://pecl.php.net/package/memcached) will be used. |
71
|
|
|
* If false, [memcache](http://pecl.php.net/package/memcache) will be used. |
72
|
|
|
* Defaults to false. |
73
|
|
|
*/ |
74
|
|
|
public $useMemcached = false; |
75
|
|
|
/** |
76
|
|
|
* @var string an ID that identifies a Memcached instance. This property is used only when [[useMemcached]] is true. |
77
|
|
|
* By default the Memcached instances are destroyed at the end of the request. To create an instance that |
78
|
|
|
* persists between requests, you may specify a unique ID for the instance. All instances created with the |
79
|
|
|
* same ID will share the same connection. |
80
|
|
|
* @see http://ca2.php.net/manual/en/memcached.construct.php |
81
|
|
|
*/ |
82
|
|
|
public $persistentId; |
83
|
|
|
/** |
84
|
|
|
* @var array options for Memcached. This property is used only when [[useMemcached]] is true. |
85
|
|
|
* @see http://ca2.php.net/manual/en/memcached.setoptions.php |
86
|
|
|
*/ |
87
|
|
|
public $options; |
88
|
|
|
/** |
89
|
|
|
* @var string memcached sasl username. This property is used only when [[useMemcached]] is true. |
90
|
|
|
* @see http://php.net/manual/en/memcached.setsaslauthdata.php |
91
|
|
|
*/ |
92
|
|
|
public $username; |
93
|
|
|
/** |
94
|
|
|
* @var string memcached sasl password. This property is used only when [[useMemcached]] is true. |
95
|
|
|
* @see http://php.net/manual/en/memcached.setsaslauthdata.php |
96
|
|
|
*/ |
97
|
|
|
public $password; |
98
|
|
|
|
99
|
|
|
/** |
100
|
|
|
* @var \Memcache|\Memcached the Memcache instance |
101
|
|
|
*/ |
102
|
|
|
private $_cache; |
103
|
|
|
/** |
104
|
|
|
* @var array list of memcache server configurations |
105
|
|
|
*/ |
106
|
|
|
private $_servers = []; |
107
|
|
|
|
108
|
|
|
|
109
|
|
|
/** |
110
|
|
|
* Initializes this application component. |
111
|
|
|
* It creates the memcache instance and adds memcache servers. |
112
|
|
|
*/ |
113
|
16 |
|
public function init() |
114
|
|
|
{ |
115
|
16 |
|
parent::init(); |
116
|
16 |
|
$this->addServers($this->getMemcache(), $this->getServers()); |
117
|
16 |
|
} |
118
|
|
|
|
119
|
|
|
/** |
120
|
|
|
* Add servers to the server pool of the cache specified |
121
|
|
|
* |
122
|
|
|
* @param \Memcache|\Memcached $cache |
123
|
|
|
* @param MemCacheServer[] $servers |
124
|
|
|
* @throws InvalidConfigException |
125
|
|
|
*/ |
126
|
16 |
|
protected function addServers($cache, $servers) |
127
|
|
|
{ |
128
|
16 |
|
if (empty($servers)) { |
129
|
16 |
|
$servers = [new MemCacheServer([ |
130
|
16 |
|
'host' => '127.0.0.1', |
131
|
|
|
'port' => 11211, |
132
|
|
|
])]; |
133
|
|
|
} else { |
134
|
|
|
foreach ($servers as $server) { |
135
|
|
|
if ($server->host === null) { |
136
|
|
|
throw new InvalidConfigException("The 'host' property must be specified for every memcache server."); |
137
|
|
|
} |
138
|
|
|
} |
139
|
|
|
} |
140
|
16 |
|
if ($this->useMemcached) { |
141
|
16 |
|
$this->addMemcachedServers($cache, $servers); |
|
|
|
|
142
|
|
|
} else { |
143
|
|
|
$this->addMemcacheServers($cache, $servers); |
|
|
|
|
144
|
|
|
} |
145
|
16 |
|
} |
146
|
|
|
|
147
|
|
|
/** |
148
|
|
|
* Add servers to the server pool of the cache specified |
149
|
|
|
* Used for memcached PECL extension. |
150
|
|
|
* |
151
|
|
|
* @param \Memcached $cache |
152
|
|
|
* @param MemCacheServer[] $servers |
153
|
|
|
*/ |
154
|
16 |
|
protected function addMemcachedServers($cache, $servers) |
155
|
|
|
{ |
156
|
16 |
|
$existingServers = []; |
157
|
16 |
|
if ($this->persistentId !== null) { |
158
|
|
|
foreach ($cache->getServerList() as $s) { |
159
|
|
|
$existingServers[$s['host'] . ':' . $s['port']] = true; |
160
|
|
|
} |
161
|
|
|
} |
162
|
16 |
|
foreach ($servers as $server) { |
163
|
16 |
|
if (empty($existingServers) || !isset($existingServers[$server->host . ':' . $server->port])) { |
164
|
16 |
|
$cache->addServer($server->host, $server->port, $server->weight); |
165
|
|
|
} |
166
|
|
|
} |
167
|
16 |
|
} |
168
|
|
|
|
169
|
|
|
/** |
170
|
|
|
* Add servers to the server pool of the cache specified |
171
|
|
|
* Used for memcache PECL extension. |
172
|
|
|
* |
173
|
|
|
* @param \Memcache $cache |
174
|
|
|
* @param MemCacheServer[] $servers |
175
|
|
|
*/ |
176
|
|
|
protected function addMemcacheServers($cache, $servers) |
177
|
|
|
{ |
178
|
|
|
$class = new \ReflectionClass($cache); |
179
|
|
|
$paramCount = $class->getMethod('addServer')->getNumberOfParameters(); |
180
|
|
|
foreach ($servers as $server) { |
181
|
|
|
// $timeout is used for memcache versions that do not have $timeoutms parameter |
182
|
|
|
$timeout = (int) ($server->timeout / 1000) + (($server->timeout % 1000 > 0) ? 1 : 0); |
183
|
|
|
if ($paramCount === 9) { |
184
|
|
|
$cache->addserver( |
185
|
|
|
$server->host, |
186
|
|
|
$server->port, |
187
|
|
|
$server->persistent, |
188
|
|
|
$server->weight, |
189
|
|
|
$timeout, |
190
|
|
|
$server->retryInterval, |
191
|
|
|
$server->status, |
192
|
|
|
$server->failureCallback, |
193
|
|
|
$server->timeout |
194
|
|
|
); |
195
|
|
|
} else { |
196
|
|
|
$cache->addserver( |
197
|
|
|
$server->host, |
198
|
|
|
$server->port, |
199
|
|
|
$server->persistent, |
200
|
|
|
$server->weight, |
201
|
|
|
$timeout, |
202
|
|
|
$server->retryInterval, |
203
|
|
|
$server->status, |
204
|
|
|
$server->failureCallback |
205
|
|
|
); |
206
|
|
|
} |
207
|
|
|
} |
208
|
|
|
} |
209
|
|
|
|
210
|
|
|
/** |
211
|
|
|
* Returns the underlying memcache (or memcached) object. |
212
|
|
|
* @return \Memcache|\Memcached the memcache (or memcached) object used by this cache component. |
213
|
|
|
* @throws InvalidConfigException if memcache or memcached extension is not loaded |
214
|
|
|
*/ |
215
|
16 |
|
public function getMemcache() |
216
|
|
|
{ |
217
|
16 |
|
if ($this->_cache === null) { |
218
|
16 |
|
$extension = $this->useMemcached ? 'memcached' : 'memcache'; |
219
|
16 |
|
if (!extension_loaded($extension)) { |
220
|
|
|
throw new InvalidConfigException("MemCache requires PHP $extension extension to be loaded."); |
221
|
|
|
} |
222
|
|
|
|
223
|
16 |
|
if ($this->useMemcached) { |
224
|
16 |
|
$this->_cache = $this->persistentId !== null ? new \Memcached($this->persistentId) : new \Memcached; |
225
|
16 |
|
if ($this->username !== null || $this->password !== null) { |
226
|
|
|
$this->_cache->setOption(\Memcached::OPT_BINARY_PROTOCOL, true); |
227
|
|
|
$this->_cache->setSaslAuthData($this->username, $this->password); |
228
|
|
|
} |
229
|
16 |
|
if (!empty($this->options)) { |
230
|
|
|
$this->_cache->setOptions($this->options); |
|
|
|
|
231
|
|
|
} |
232
|
|
|
} else { |
233
|
|
|
$this->_cache = new \Memcache; |
234
|
|
|
} |
235
|
|
|
} |
236
|
|
|
|
237
|
16 |
|
return $this->_cache; |
238
|
|
|
} |
239
|
|
|
|
240
|
|
|
/** |
241
|
|
|
* Returns the memcache or memcached server configurations. |
242
|
|
|
* @return MemCacheServer[] list of memcache server configurations. |
243
|
|
|
*/ |
244
|
16 |
|
public function getServers() |
245
|
|
|
{ |
246
|
16 |
|
return $this->_servers; |
247
|
|
|
} |
248
|
|
|
|
249
|
|
|
/** |
250
|
|
|
* @param array $config list of memcache or memcached server configurations. Each element must be an array |
251
|
|
|
* with the following keys: host, port, persistent, weight, timeout, retryInterval, status. |
252
|
|
|
* @see http://php.net/manual/en/memcache.addserver.php |
253
|
|
|
* @see http://php.net/manual/en/memcached.addserver.php |
254
|
|
|
*/ |
255
|
|
|
public function setServers($config) |
256
|
|
|
{ |
257
|
|
|
foreach ($config as $c) { |
258
|
|
|
$this->_servers[] = new MemCacheServer($c); |
259
|
|
|
} |
260
|
|
|
} |
261
|
|
|
|
262
|
|
|
/** |
263
|
|
|
* Retrieves a value from cache with a specified key. |
264
|
|
|
* This is the implementation of the method declared in the parent class. |
265
|
|
|
* @param string $key a unique key identifying the cached value |
266
|
|
|
* @return mixed|false the value stored in cache, false if the value is not in the cache or expired. |
267
|
|
|
*/ |
268
|
13 |
|
protected function getValue($key) |
269
|
|
|
{ |
270
|
13 |
|
return $this->_cache->get($key); |
271
|
|
|
} |
272
|
|
|
|
273
|
|
|
/** |
274
|
|
|
* Retrieves multiple values from cache with the specified keys. |
275
|
|
|
* @param array $keys a list of keys identifying the cached values |
276
|
|
|
* @return array a list of cached values indexed by the keys |
277
|
|
|
*/ |
278
|
2 |
|
protected function getValues($keys) |
279
|
|
|
{ |
280
|
2 |
|
return $this->useMemcached ? $this->_cache->getMulti($keys) : $this->_cache->get($keys); |
|
|
|
|
281
|
|
|
} |
282
|
|
|
|
283
|
|
|
/** |
284
|
|
|
* Stores a value identified by a key in cache. |
285
|
|
|
* This is the implementation of the method declared in the parent class. |
286
|
|
|
* |
287
|
|
|
* @param string $key the key identifying the value to be cached |
288
|
|
|
* @param mixed $value the value to be cached. |
289
|
|
|
* @see [Memcache::set()](http://php.net/manual/en/memcache.set.php) |
290
|
|
|
* @param int $duration the number of seconds in which the cached value will expire. 0 means never expire. |
291
|
|
|
* @return bool true if the value is successfully stored into cache, false otherwise |
292
|
|
|
*/ |
293
|
12 |
|
protected function setValue($key, $value, $duration) |
294
|
|
|
{ |
295
|
|
|
// Use UNIX timestamp since it doesn't have any limitation |
296
|
|
|
// @see http://php.net/manual/en/memcache.set.php |
297
|
|
|
// @see http://php.net/manual/en/memcached.expiration.php |
298
|
12 |
|
$expire = $duration > 0 ? $duration + time() : 0; |
299
|
|
|
|
300
|
12 |
|
return $this->useMemcached ? $this->_cache->set($key, $value, $expire) : $this->_cache->set($key, $value, 0, $expire); |
301
|
|
|
} |
302
|
|
|
|
303
|
|
|
/** |
304
|
|
|
* Stores multiple key-value pairs in cache. |
305
|
|
|
* @param array $data array where key corresponds to cache key while value is the value stored |
306
|
|
|
* @param int $duration the number of seconds in which the cached values will expire. 0 means never expire. |
307
|
|
|
* @return array array of failed keys. |
308
|
|
|
*/ |
309
|
3 |
|
protected function setValues($data, $duration) |
310
|
|
|
{ |
311
|
3 |
|
if ($this->useMemcached) { |
312
|
|
|
// Use UNIX timestamp since it doesn't have any limitation |
313
|
|
|
// @see http://php.net/manual/en/memcache.set.php |
314
|
|
|
// @see http://php.net/manual/en/memcached.expiration.php |
315
|
3 |
|
$expire = $duration > 0 ? $duration + time() : 0; |
316
|
|
|
|
317
|
|
|
// Memcached::setMulti() returns boolean |
318
|
|
|
// @see http://php.net/manual/en/memcached.setmulti.php |
319
|
3 |
|
return $this->_cache->setMulti($data, $expire) ? [] : array_keys($data); |
|
|
|
|
320
|
|
|
} else { |
321
|
|
|
return parent::setValues($data, $duration); |
322
|
|
|
} |
323
|
|
|
} |
324
|
|
|
|
325
|
|
|
/** |
326
|
|
|
* Stores a value identified by a key into cache if the cache does not contain this key. |
327
|
|
|
* This is the implementation of the method declared in the parent class. |
328
|
|
|
* |
329
|
|
|
* @param string $key the key identifying the value to be cached |
330
|
|
|
* @param mixed $value the value to be cached |
331
|
|
|
* @see [Memcache::set()](http://php.net/manual/en/memcache.set.php) |
332
|
|
|
* @param int $duration the number of seconds in which the cached value will expire. 0 means never expire. |
333
|
|
|
* @return bool true if the value is successfully stored into cache, false otherwise |
334
|
|
|
*/ |
335
|
2 |
|
protected function addValue($key, $value, $duration) |
336
|
|
|
{ |
337
|
|
|
// Use UNIX timestamp since it doesn't have any limitation |
338
|
|
|
// @see http://php.net/manual/en/memcache.set.php |
339
|
|
|
// @see http://php.net/manual/en/memcached.expiration.php |
340
|
2 |
|
$expire = $duration > 0 ? $duration + time() : 0; |
341
|
|
|
|
342
|
2 |
|
return $this->useMemcached ? $this->_cache->add($key, $value, $expire) : $this->_cache->add($key, $value, 0, $expire); |
343
|
|
|
} |
344
|
|
|
|
345
|
|
|
/** |
346
|
|
|
* Deletes a value with the specified key from cache |
347
|
|
|
* This is the implementation of the method declared in the parent class. |
348
|
|
|
* @param string $key the key of the value to be deleted |
349
|
|
|
* @return bool if no error happens during deletion |
350
|
|
|
*/ |
351
|
1 |
|
protected function deleteValue($key) |
352
|
|
|
{ |
353
|
1 |
|
return $this->_cache->delete($key, 0); |
354
|
|
|
} |
355
|
|
|
|
356
|
|
|
/** |
357
|
|
|
* Deletes all values from cache. |
358
|
|
|
* This is the implementation of the method declared in the parent class. |
359
|
|
|
* @return bool whether the flush operation was successful. |
360
|
|
|
*/ |
361
|
11 |
|
protected function flushValues() |
362
|
|
|
{ |
363
|
11 |
|
return $this->_cache->flush(); |
364
|
|
|
} |
365
|
|
|
} |
366
|
|
|
|
This check looks at variables that have been passed in as parameters and are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.