1 | <?php |
||
2 | /** |
||
3 | * |
||
4 | * @package supernova |
||
5 | * @version #43b0# |
||
6 | * @copyright (c) 2009-2017 Gorlum for http://supernova.ws |
||
7 | * @license http://opensource.org/licenses/gpl-license.php GNU Public License |
||
8 | * |
||
9 | */ |
||
10 | |||
11 | /** |
||
12 | * |
||
13 | * Basic cacher class that handles different cache engines |
||
14 | * It's pretty smart to handle one cache instance for all application instances (if there is PHP-cacher installed) |
||
15 | * Currently supported only XCache and no-cache (array) |
||
16 | * With no-cache some advanced features would be unaccessible |
||
17 | * Cacher works not only with single values. It's also support multidimensional arrays |
||
18 | * Currently support is a bit limited - for example there is no "walk" function. However basic array abilities supported |
||
19 | * You should NEVER operate with arrays inside of cacher and should ALWAYS use wrap-up functions |
||
20 | * |
||
21 | * @property bool _INITIALIZED |
||
22 | * @property array lng_stat_usage - Array for locale strings usage statistics |
||
23 | * @property array tables |
||
24 | * |
||
25 | * @package supernova |
||
26 | */ |
||
27 | class classCache implements ArrayAccess { |
||
28 | /** |
||
29 | * CACHER_NOT_INIT - not initialized |
||
30 | */ |
||
31 | const CACHER_NOT_INIT = -1; |
||
32 | /** |
||
33 | * CACHER_NO_CACHE - no cache - array() used |
||
34 | */ |
||
35 | const CACHER_NO_CACHE = 0; |
||
36 | /** |
||
37 | * CACHER_XCACHE - xCache |
||
38 | */ |
||
39 | const CACHER_XCACHE = 1; |
||
40 | |||
41 | /** |
||
42 | * @var int $mode - cacher mode |
||
43 | */ |
||
44 | protected static $mode = self::CACHER_NOT_INIT; |
||
45 | /** |
||
46 | * @var array $data - Cacher data |
||
47 | */ |
||
48 | protected static $data; |
||
49 | /** |
||
50 | * @var string $prefix - Cacher prefix |
||
51 | */ |
||
52 | protected $prefix; |
||
53 | |||
54 | /** |
||
55 | * @var $cacheObject static - Singleton object |
||
0 ignored issues
–
show
Documentation
Bug
introduced
by
![]() |
|||
56 | */ |
||
57 | protected static $cacheObject; |
||
58 | |||
59 | public function __construct($prefIn = 'CACHE_', $init_mode = false) { |
||
60 | if (!($init_mode === false || $init_mode === self::CACHER_NO_CACHE || ($init_mode === self::CACHER_XCACHE && extension_loaded('xcache')))) { |
||
61 | throw new UnexpectedValueException('Wrong work mode or current mode does not supported on your server'); |
||
62 | } |
||
63 | |||
64 | $this->prefix = $prefIn; |
||
65 | if (extension_loaded('xcache') && ($init_mode === self::CACHER_XCACHE || $init_mode === false)) { |
||
66 | if (self::$mode === self::CACHER_NOT_INIT) { |
||
67 | self::$mode = self::CACHER_XCACHE; |
||
68 | } |
||
69 | } else { |
||
70 | if (self::$mode === self::CACHER_NOT_INIT) { |
||
71 | self::$mode = self::CACHER_NO_CACHE; |
||
72 | if (!self::$data) { |
||
73 | self::$data = array(); |
||
74 | } |
||
75 | } |
||
76 | } |
||
77 | } |
||
78 | |||
79 | public static function getInstance($prefIn = 'CACHE_', $table_name = '') { |
||
80 | if (!isset(self::$cacheObject)) { |
||
81 | $className = get_class(); |
||
82 | self::$cacheObject = new $className($prefIn); |
||
83 | } |
||
84 | |||
85 | return self::$cacheObject; |
||
86 | } |
||
87 | |||
88 | public final function __clone() { |
||
89 | // You NEVER need to copy cacher object or siblings |
||
90 | throw new BadMethodCallException('Clone is not allowed'); |
||
91 | } |
||
92 | |||
93 | /** |
||
94 | * @return int |
||
95 | */ |
||
96 | public function getMode() { |
||
97 | return self::$mode; |
||
98 | } |
||
99 | |||
100 | /** |
||
101 | * @return string |
||
102 | */ |
||
103 | public function getPrefix() { |
||
104 | return $this->prefix; |
||
105 | } |
||
106 | |||
107 | /** |
||
108 | * @param $prefix |
||
109 | */ |
||
110 | public function setPrefix($prefix) { |
||
111 | $this->prefix = $prefix; |
||
112 | } |
||
113 | |||
114 | // ------------------------------------------------------------------------- |
||
115 | // Here comes low-level functions - those that directly works with cacher engines |
||
116 | // ------------------------------------------------------------------------- |
||
117 | public function __set($name, $value) { |
||
118 | switch (self::$mode) { |
||
119 | case self::CACHER_NO_CACHE: |
||
120 | self::$data[$this->prefix . $name] = $value; |
||
121 | break; |
||
122 | |||
123 | case self::CACHER_XCACHE: |
||
124 | xcache_set($this->prefix . $name, $value); |
||
125 | break; |
||
126 | } |
||
127 | } |
||
128 | |||
129 | public function __get($name) { |
||
130 | switch (self::$mode) { |
||
131 | case self::CACHER_NO_CACHE: |
||
132 | return array_key_exists($this->prefix . $name, self::$data) ? self::$data[$this->prefix . $name] : null; |
||
133 | break; |
||
134 | |||
135 | case self::CACHER_XCACHE: |
||
136 | return xcache_get($this->prefix . $name); |
||
137 | break; |
||
138 | } |
||
139 | |||
140 | return null; |
||
141 | } |
||
142 | |||
143 | public function __isset($name) { |
||
144 | switch (self::$mode) { |
||
145 | case self::CACHER_NO_CACHE: |
||
146 | return isset(self::$data[$this->prefix . $name]); |
||
147 | break; |
||
148 | |||
149 | case self::CACHER_XCACHE: |
||
150 | return xcache_isset($this->prefix . $name) && ($this->__get($name) !== null); |
||
151 | break; |
||
152 | } |
||
153 | |||
154 | return false; |
||
155 | } |
||
156 | |||
157 | public function __unset($name) { |
||
158 | switch (self::$mode) { |
||
159 | case self::CACHER_NO_CACHE: |
||
160 | unset(self::$data[$this->prefix . $name]); |
||
161 | break; |
||
162 | |||
163 | case self::CACHER_XCACHE: |
||
164 | xcache_unset($this->prefix . $name); |
||
165 | break; |
||
166 | } |
||
167 | } |
||
168 | |||
169 | public function unset_by_prefix($prefix_unset = '') { |
||
170 | static $array_clear; |
||
171 | !$array_clear ? $array_clear = function (&$v, $k, $p) { |
||
172 | strpos($k, $p) === 0 ? $v = null : false; |
||
173 | } : false; |
||
174 | |||
175 | switch (self::$mode) { |
||
176 | case self::CACHER_NO_CACHE: |
||
177 | // array_walk(self::$data, create_function('&$v,$k,$p', 'if(strpos($k, $p) === 0)$v = NULL;'), $this->prefix.$prefix_unset); |
||
178 | array_walk(self::$data, $array_clear, $this->prefix . $prefix_unset); |
||
179 | |||
180 | return true; |
||
181 | break; |
||
182 | |||
183 | case self::CACHER_XCACHE: |
||
184 | if (!function_exists('xcache_unset_by_prefix')) { |
||
185 | return false; |
||
186 | } |
||
187 | |||
188 | set_time_limit(300); // TODO - Optimize |
||
189 | $result = xcache_unset_by_prefix($this->prefix . $prefix_unset); |
||
190 | set_time_limit(30); // TODO - Optimize |
||
191 | |||
192 | return $result; |
||
193 | break; |
||
194 | } |
||
195 | |||
196 | return true; |
||
197 | } |
||
198 | // ------------------------------------------------------------------------- |
||
199 | // End of low-level functions |
||
200 | // ------------------------------------------------------------------------- |
||
201 | |||
202 | protected function make_element_name($args, $diff = 0) { |
||
203 | $num_args = count($args); |
||
204 | |||
205 | if ($num_args < 1) { |
||
206 | return false; |
||
207 | } |
||
208 | |||
209 | $name = ''; |
||
210 | $aName = array(); |
||
211 | for ($i = 0; $i <= $num_args - 1 - $diff; $i++) { |
||
212 | $name .= "[{$args[$i]}]"; |
||
213 | array_unshift($aName, $name); |
||
214 | } |
||
215 | |||
216 | return $aName; |
||
217 | } |
||
218 | |||
219 | public function array_set() { |
||
220 | $args = func_get_args(); |
||
221 | $name = $this->make_element_name($args, 1); |
||
222 | |||
223 | if (!$name) { |
||
224 | return null; |
||
225 | } |
||
226 | |||
227 | if ($this->$name[0] === null) { |
||
228 | for ($i = count($name) - 1; $i > 0; $i--) { |
||
229 | $cName = "{$name[$i]}_COUNT"; |
||
230 | $cName1 = "{$name[$i-1]}_COUNT"; |
||
231 | if ($this->$cName1 == null || $i == 1) { |
||
232 | $this->$cName++; |
||
233 | } |
||
234 | } |
||
235 | } |
||
236 | |||
237 | $this->$name[0] = $args[count($args) - 1]; |
||
238 | |||
239 | return true; |
||
240 | } |
||
241 | |||
242 | public function array_get() { |
||
243 | $name = $this->make_element_name(func_get_args()); |
||
244 | if (!$name) { |
||
245 | return null; |
||
246 | } |
||
247 | |||
248 | return $this->$name[0]; |
||
249 | } |
||
250 | |||
251 | public function array_count() { |
||
252 | $name = $this->make_element_name(func_get_args()); |
||
253 | if (!$name) { |
||
254 | return 0; |
||
255 | } |
||
256 | $cName = "{$name[0]}_COUNT"; |
||
257 | $retVal = $this->$cName; |
||
258 | if (!$retVal) { |
||
259 | $retVal = null; |
||
260 | } |
||
261 | |||
262 | return $retVal; |
||
263 | } |
||
264 | |||
265 | public function array_unset() { |
||
266 | $name = $this->make_element_name(func_get_args()); |
||
267 | |||
268 | if (!$name) { |
||
269 | return false; |
||
270 | } |
||
271 | $this->unset_by_prefix($name[0]); |
||
272 | |||
273 | $count = count($name); |
||
274 | for ($i = 1; $i < $count; $i++) { |
||
275 | $cName = "{$name[$i]}_COUNT"; |
||
276 | $cName1 = "{$name[$i-1]}_COUNT"; |
||
277 | |||
278 | if ($i == 1 || $this->$cName1 === null) { |
||
279 | $this->$cName--; |
||
280 | if ($this->$cName <= 0) { |
||
281 | unset($this->$cName); |
||
282 | } |
||
283 | } |
||
284 | } |
||
285 | |||
286 | return true; |
||
287 | } |
||
288 | |||
289 | public function dumpData() { |
||
290 | switch (self::$mode) { |
||
291 | case self::CACHER_NO_CACHE: |
||
292 | return dump(self::$data, $this->prefix); |
||
293 | break; |
||
294 | |||
295 | default: |
||
296 | return false; |
||
297 | break; |
||
298 | } |
||
299 | } |
||
300 | |||
301 | public function reset() { |
||
302 | $this->unset_by_prefix(); |
||
303 | |||
304 | $this->_INITIALIZED = false; |
||
305 | } |
||
306 | |||
307 | public function init($reInit = false) { |
||
308 | $this->_INITIALIZED = true; |
||
309 | } |
||
310 | |||
311 | public function isInitialized() { |
||
312 | return $this->_INITIALIZED; |
||
313 | } |
||
314 | |||
315 | /** |
||
316 | * Whether a offset exists |
||
317 | * @link http://php.net/manual/en/arrayaccess.offsetexists.php |
||
318 | * |
||
319 | * @param mixed $offset <p> |
||
320 | * An offset to check for. |
||
321 | * </p> |
||
322 | * |
||
323 | * @return boolean true on success or false on failure. |
||
324 | * </p> |
||
325 | * <p> |
||
326 | * The return value will be casted to boolean if non-boolean was returned. |
||
327 | * @since 5.0.0 |
||
328 | */ |
||
329 | public function offsetExists($offset) { |
||
330 | return $this->__isset($offset); |
||
331 | } |
||
332 | |||
333 | /** |
||
334 | * Offset to retrieve |
||
335 | * @link http://php.net/manual/en/arrayaccess.offsetget.php |
||
336 | * |
||
337 | * @param mixed $offset <p> |
||
338 | * The offset to retrieve. |
||
339 | * </p> |
||
340 | * |
||
341 | * @return mixed Can return all value types. |
||
342 | * @since 5.0.0 |
||
343 | */ |
||
344 | public function offsetGet($offset) { |
||
345 | return $this->__get($offset); |
||
346 | } |
||
347 | |||
348 | /** |
||
349 | * Offset to set |
||
350 | * @link http://php.net/manual/en/arrayaccess.offsetset.php |
||
351 | * |
||
352 | * @param mixed $offset <p> |
||
353 | * The offset to assign the value to. |
||
354 | * </p> |
||
355 | * @param mixed $value <p> |
||
356 | * The value to set. |
||
357 | * </p> |
||
358 | * |
||
359 | * @return void |
||
360 | * @since 5.0.0 |
||
361 | */ |
||
362 | public function offsetSet($offset, $value) { |
||
363 | $this->__set($offset, $value); |
||
364 | } |
||
365 | |||
366 | /** |
||
367 | * Offset to unset |
||
368 | * @link http://php.net/manual/en/arrayaccess.offsetunset.php |
||
369 | * |
||
370 | * @param mixed $offset <p> |
||
371 | * The offset to unset. |
||
372 | * </p> |
||
373 | * |
||
374 | * @return void |
||
375 | * @since 5.0.0 |
||
376 | */ |
||
377 | public function offsetUnset($offset) { |
||
378 | $this->__unset($offset); |
||
379 | } |
||
380 | |||
381 | } |
||
382 |