1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Ezcache\Cache; |
4
|
|
|
|
5
|
|
|
/** |
6
|
|
|
* @codeCoverageIgnore |
7
|
|
|
* @author: William Johnson dos Santos Okano <[email protected]> |
8
|
|
|
*/ |
9
|
|
|
class MemCached implements CacheInterface |
10
|
|
|
{ |
11
|
|
|
/** @var string */ |
12
|
|
|
private $namespace; |
13
|
|
|
|
14
|
|
|
/** @var int */ |
15
|
|
|
private $ttl; |
16
|
|
|
|
17
|
|
|
/** @var \Memcached */ |
18
|
|
|
private $memcachedInstance; |
19
|
|
|
|
20
|
|
|
/** |
21
|
|
|
* MemCached constructor. |
22
|
|
|
* |
23
|
|
|
* @param \Memcached $memcached the memcached instance |
24
|
|
|
* @param int $ttl the cache lifetime in seconds (0 = Forever) |
25
|
|
|
* @param string $namespace the cache namespace |
26
|
|
|
*/ |
27
|
|
|
public function __construct(\Memcached $memcached, $ttl = 0, string $namespace = null) |
28
|
|
|
{ |
29
|
|
|
$this->ttl = $ttl; |
30
|
|
|
$this->memcachedInstance = $memcached; |
31
|
|
|
if ($namespace !== null) { |
32
|
|
|
$this->setNamespace($namespace); |
33
|
|
|
} |
34
|
|
|
} |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* Set the cache namespace. |
38
|
|
|
* |
39
|
|
|
* @param string $namespace the cache namespace |
40
|
|
|
* |
41
|
|
|
* @return bool true on success or false on failure |
42
|
|
|
*/ |
43
|
|
|
public function setNamespace(string $namespace) : bool |
44
|
|
|
{ |
45
|
|
|
$this->namespace = $namespace; |
46
|
|
|
|
47
|
|
|
return true; |
48
|
|
|
} |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* Set a value to a key on cache. |
52
|
|
|
* |
53
|
|
|
* @param string $key the key to be set. |
54
|
|
|
* @param mixed $value the correspondent value of that cache key. |
55
|
|
|
* @param int|null $ttl the cache life time in seconds (If no value passed will use the default value). |
56
|
|
|
* |
57
|
|
|
* @return bool true on success or false on failure. |
58
|
|
|
*/ |
59
|
|
View Code Duplication |
public function set(string $key, $value, int $ttl = null) : bool |
|
|
|
|
60
|
|
|
{ |
61
|
|
|
$ttl = $ttl ?? $this->ttl; |
62
|
|
|
$key = $this->namespacedKey($key); |
63
|
|
|
|
64
|
|
|
return $this->memcachedInstance->set($key, $value, $ttl); |
65
|
|
|
} |
66
|
|
|
|
67
|
|
|
/** |
68
|
|
|
* Return the valid cache value stored with the given key. |
69
|
|
|
* |
70
|
|
|
* @param string $key the cache key to be found. |
71
|
|
|
* |
72
|
|
|
* @return mixed the data found. |
73
|
|
|
*/ |
74
|
|
View Code Duplication |
public function get(string $key) |
|
|
|
|
75
|
|
|
{ |
76
|
|
|
$key = $this->namespacedKey($key); |
77
|
|
|
$value = $this->memcachedInstance->get($key); |
78
|
|
|
if ($this->exists($key)) { |
79
|
|
|
return $value; |
80
|
|
|
} |
81
|
|
|
} |
82
|
|
|
|
83
|
|
|
/** |
84
|
|
|
* Delete cache especified by key. |
85
|
|
|
* |
86
|
|
|
* @param string $key the cache key to be deleted. |
87
|
|
|
* |
88
|
|
|
* @return bool true on success or false on failure. |
89
|
|
|
*/ |
90
|
|
|
public function delete(string $key) : bool |
91
|
|
|
{ |
92
|
|
|
$key = $this->namespacedKey($key); |
93
|
|
|
|
94
|
|
|
return $this->memcachedInstance->delete($key); |
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
/** |
98
|
|
|
* Check if given key exists and is valid on cache. |
99
|
|
|
* |
100
|
|
|
* @param string $key the cache key to be verified. |
101
|
|
|
* @param bool $isValid if set to true the function will verify if it is valid (not expired). |
102
|
|
|
* |
103
|
|
|
* @return bool true if exists false otherwise. |
104
|
|
|
*/ |
105
|
|
|
public function exists(string $key, bool $isValid = false) : bool |
106
|
|
|
{ |
107
|
|
|
$this->memcachedInstance->get($key); |
108
|
|
|
|
109
|
|
|
return $this->memcachedInstance->getResultCode() !== \Memcached::RES_NOTFOUND; |
110
|
|
|
} |
111
|
|
|
|
112
|
|
|
/** |
113
|
|
|
* Renew the cache expiration time. |
114
|
|
|
* |
115
|
|
|
* @param string $key the cache key to be renewed. |
116
|
|
|
* @param int|null $ttl extra time to live in seconds. |
117
|
|
|
* |
118
|
|
|
* @return bool true on success or false on failure. |
119
|
|
|
*/ |
120
|
|
|
public function renew(string $key, int $ttl) : bool |
121
|
|
|
{ |
122
|
|
|
$key = $this->namespacedKey($key); |
123
|
|
|
$ttl = $ttl ?? $this->ttl; |
124
|
|
|
if ($this->exists($key)) { |
125
|
|
|
return $this->memcachedInstance->touch($key, $ttl); |
126
|
|
|
} |
127
|
|
|
|
128
|
|
|
return false; |
129
|
|
|
} |
130
|
|
|
|
131
|
|
|
/** |
132
|
|
|
* Clear all cache records.If namespace set, just clear those that starts with the namespace. |
133
|
|
|
* |
134
|
|
|
* @param string|null $namespace the cache namespace. |
135
|
|
|
* |
136
|
|
|
* @return bool true on success or false on failure. |
137
|
|
|
*/ |
138
|
|
|
public function clear(string $namespace = null) : bool |
139
|
|
|
{ |
140
|
|
|
$namespace = $namespace ?? $this->namespace; |
141
|
|
|
if ($namespace === null) { |
142
|
|
|
return $this->memcachedInstance->flush(); |
143
|
|
|
} |
144
|
|
|
|
145
|
|
|
// Find all keys, iterate and them delete the only ones that starts with the namespace |
146
|
|
|
$cacheKeys = $this->memcachedInstance->getAllKeys(); |
147
|
|
|
$filteredCacheKeys = array_filter($cacheKeys, function ($key) use ($namespace) { |
148
|
|
|
return strpos($key, $namespace) === 0; |
149
|
|
|
}); |
150
|
|
|
|
151
|
|
|
array_walk($filteredCacheKeys, [$this, 'delete']); |
152
|
|
|
|
153
|
|
|
return true; |
154
|
|
|
} |
155
|
|
|
|
156
|
|
|
/** |
157
|
|
|
* Return the key with the namespace. Since Memcached doesn't support namespaces |
158
|
|
|
* the method just simulate it by pre-pending some fixed string to the key. |
159
|
|
|
* |
160
|
|
|
* @param string $key the key to prepend the namespace, if necessary |
161
|
|
|
* |
162
|
|
|
* @return string the "namespaced" key |
163
|
|
|
*/ |
164
|
|
|
private function namespacedKey(string $key) : string |
165
|
|
|
{ |
166
|
|
|
if ($this->namespace !== null) { |
167
|
|
|
return $this->namespace.$key; |
168
|
|
|
} |
169
|
|
|
|
170
|
|
|
return $key; |
171
|
|
|
} |
172
|
|
|
} |
173
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.