Issues (1369)

classes/classCache.php (1 issue)

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
The doc comment $cacheObject at position 0 could not be parsed: Unknown type name '$cacheObject' at position 0 in $cacheObject.
Loading history...
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