PluginProbe
Powered Cache – Caching and Optimization for WordPress – Easily Improve PageSpeed & Web Vitals Score / 2.0.3
Powered Cache – Caching and Optimization for WordPress – Easily Improve PageSpeed & Web Vitals Score v2.0.3
trunk 1.0 1.0.1 1.1 1.1.1 1.1.2 1.2 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 2.0 2.0.1 2.0.2 2.0.3 2.0.4 2.1 2.1.1 2.1.2 2.2 2.2.1 All 69 releases
powered-cache / includes / dropins / apcu-object-cache.php

apcu-object-cache.php in Powered Cache – Caching and Optimization for WordPress – Easily Improve PageSpeed & Web Vitals Score 2.0.3, at includes/dropins/apcu-object-cache.php

1,166 lines 29.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * APCu drop-in
5 *
6 * @link https://github.com/l3rady/WordPress-APCu-Object-Cache
7 */
8
9 if ( ! function_exists( 'apcu_add' ) ) {
10 return;
11 }
12 // Stop direct access
13 defined( 'ABSPATH' ) or exit;
14
15
16 /**
17 * Adds data to the cache, if the cache key does not already exist.
18 *
19 * @param int|string $key The cache key to use for retrieval later
20 * @param mixed $data The data to add to the cache store
21 * @param string $group The group to add the cache to
22 * @param int $expire When the cache data should be expired
23 *
24 * @return bool False if cache key and group already exist, true on success
25 */
26 function wp_cache_add( $key, $data, $group = 'default', $expire = 0 ) {
27 return WP_Object_Cache::instance()->add( $key, $data, $group, $expire );
28 }
29
30
31 /**
32 * Closes the cache.
33 *
34 * This function has ceased to do anything since WordPress 2.5. The
35 * functionality was removed along with the rest of the persistent cache. This
36 * does not mean that plugins can't implement this function when they need to
37 * make sure that the cache is cleaned up after WordPress no longer needs it.
38 *
39 * @return bool Always returns True
40 */
41 function wp_cache_close() {
42 return true;
43 }
44
45
46 /**
47 * Decrement numeric cache item's value
48 *
49 * @param int|string $key The cache key to increment
50 * @param int $offset The amount by which to decrement the item's value. Default is 1.
51 * @param string $group The group the key is in.
52 *
53 * @return false|int False on failure, the item's new value on success.
54 */
55 function wp_cache_decr( $key, $offset = 1, $group = 'default' ) {
56 return WP_Object_Cache::instance()->decr( $key, $offset, $group );
57 }
58
59
60 /**
61 * Removes the cache contents matching key and group.
62 *
63 * @param int|string $key What the contents in the cache are called
64 * @param string $group Where the cache contents are grouped
65 *
66 * @return bool True on successful removal, false on failure
67 */
68 function wp_cache_delete( $key, $group = 'default' ) {
69 return WP_Object_Cache::instance()->delete( $key, $group );
70 }
71
72
73 /**
74 * Removes all cache items.
75 *
76 * @return bool False on failure, true on success
77 */
78 function wp_cache_flush() {
79 return WP_Object_Cache::instance()->flush();
80 }
81
82
83 /**
84 * Retrieves the cache contents from the cache by key and group.
85 *
86 * @param int|string $key What the contents in the cache are called
87 * @param string $group Where the cache contents are grouped
88 * @param bool $force Does nothing with APCu object cache
89 * @param bool &$found Whether key was found in the cache. Disambiguates a return of false, a storable value.
90 *
91 * @return bool|mixed False on failure to retrieve contents or the cache contents on success
92 */
93 function wp_cache_get( $key, $group = 'default', $force = false, &$found = null ) {
94 return WP_Object_Cache::instance()->get( $key, $group, $force, $found );
95 }
96
97
98 /**
99 * Retrieve multiple values from cache.
100 *
101 * Gets multiple values from cache, including across multiple groups
102 *
103 * Usage: array( 'group0' => array( 'key0', 'key1', 'key2', ), 'group1' => array( 'key0' ) )
104 *
105 * @param array $groups Array of groups and keys to retrieve
106 *
107 * @return array Array of cached values as
108 * array( 'group0' => array( 'key0' => 'value0', 'key1' => 'value1', 'key2' => 'value2', ) )
109 * Non-existent keys are not returned.
110 */
111 function wp_cache_get_multi( $groups ) {
112 return WP_Object_Cache::instance()->get_multi( $groups );
113 }
114
115
116 /**
117 * Increment numeric cache item's value
118 *
119 * @param int|string $key The cache key to increment
120 * @param int $offset The amount by which to increment the item's value. Default is 1.
121 * @param string $group The group the key is in.
122 *
123 * @return false|int False on failure, the item's new value on success.
124 */
125 function wp_cache_incr( $key, $offset = 1, $group = 'default' ) {
126 return WP_Object_Cache::instance()->incr( $key, $offset, $group );
127 }
128
129
130 /**
131 * Sets up Object Cache Global and assigns it.
132 *
133 * @global WP_Object_Cache $wp_object_cache WordPress Object Cache
134 */
135 function wp_cache_init() {
136 $GLOBALS['wp_object_cache'] = WP_Object_Cache::instance();
137 }
138
139
140 /**
141 * Replaces the contents of the cache with new data.
142 *
143 * @param int|string $key What to call the contents in the cache
144 * @param mixed $data The contents to store in the cache
145 * @param string $group Where to group the cache contents
146 * @param int $expire When to expire the cache contents
147 *
148 * @return bool False if not exists, true if contents were replaced
149 */
150 function wp_cache_replace( $key, $data, $group = 'default', $expire = 0 ) {
151 return WP_Object_Cache::instance()->replace( $key, $data, $group, $expire );
152 }
153
154
155 /**
156 * Saves the data to the cache.
157 *
158 * @param int|string $key What to call the contents in the cache
159 * @param mixed $data The contents to store in the cache
160 * @param string $group Where to group the cache contents
161 * @param int $expire When to expire the cache contents
162 *
163 * @return bool False on failure, true on success
164 */
165 function wp_cache_set( $key, $data, $group = 'default', $expire = 0 ) {
166 return WP_Object_Cache::instance()->set( $key, $data, $group, $expire );
167 }
168
169
170 /**
171 * Switch the internal blog id.
172 *
173 * This changes the blog id used to create keys in blog specific groups.
174 *
175 * @param int $blog_id Blog ID
176 */
177 function wp_cache_switch_to_blog( $blog_id ) {
178 WP_Object_Cache::instance()->switch_to_blog( $blog_id );
179 }
180
181
182 /**
183 * Adds a group or set of groups to the list of global groups.
184 *
185 * @param string|array $groups A group or an array of groups to add
186 */
187 function wp_cache_add_global_groups( $groups ) {
188 WP_Object_Cache::instance()->add_global_groups( $groups );
189 }
190
191
192 /**
193 * Adds a group or set of groups to the list of non-persistent groups.
194 *
195 * @param string|array $groups A group or an array of groups to add
196 */
197 function wp_cache_add_non_persistent_groups( $groups ) {
198 WP_Object_Cache::instance()->add_non_persistent_groups( $groups );
199 }
200
201
202 /**
203 * Function was depreciated and now does nothing
204 *
205 * @return bool Always returns false
206 */
207 function wp_cache_reset() {
208 _deprecated_function( __FUNCTION__, '3.5', 'wp_cache_switch_to_blog()' );
209
210 return false;
211 }
212
213
214 /**
215 * Invalidate a site's object cache
216 *
217 * @param mixed $sites Sites ID's that want flushing.
218 * Don't pass a site to flush current site
219 *
220 * @return bool
221 */
222 function wp_cache_flush_site( $sites = null ) {
223 return WP_Object_Cache::instance()->flush_sites( $sites );
224 }
225
226
227 /**
228 * Invalidate a groups object cache
229 *
230 * @param mixed $groups A group or an array of groups to invalidate
231 *
232 * @return bool
233 */
234 function wp_cache_flush_group( $groups = 'default' ) {
235 return WP_Object_Cache::instance()->flush_groups( $groups );
236 }
237
238
239 /**
240 * WordPress APCu Object Cache Backend
241 *
242 * The WordPress Object Cache is used to save on trips to the database. The
243 * APCu Object Cache stores all of the cache data to APCu and makes the cache
244 * contents available by using a key, which is used to name and later retrieve
245 * the cache contents.
246 */
247 class WP_Object_Cache {
248
249 /**
250 * @var string MD5 hash of the current installation ABSPATH
251 */
252 private $abspath;
253
254 /**
255 * @var bool Stores if APCu is available.
256 */
257 private $apcu_available;
258
259 /**
260 * @var int The sites current blog ID. This only
261 * differs if running a multi-site installations
262 */
263 private $blog_prefix;
264
265 /**
266 * @var int Keeps count of how many times the
267 * cache was successfully received from APCu
268 */
269 public $cache_hits = 0;
270
271 /**
272 * @var int Keeps count of how many times the
273 * cache was not successfully received from APCu
274 */
275 public $cache_misses = 0;
276
277 /**
278 * @var array Holds a list of cache groups that are
279 * shared across all sites in a multi-site installation
280 */
281 private $global_groups = [];
282
283 /**
284 * @var array Holds an array of versions of the retrieved groups
285 */
286 private $group_versions = [];
287
288 /**
289 * @var bool True if the current installation is a multi-site
290 */
291 private $multi_site;
292
293 /**
294 * @var array Holds cache that is to be non persistent
295 */
296 private $non_persistent_cache = [];
297
298 /**
299 * @var array Holds a list of cache groups that are not to be saved to APCu
300 */
301 private $non_persistent_groups = [];
302
303 /**
304 * @var array
305 */
306 private $local_cache = [];
307
308 /**
309 * @var array Holds an array of versions of the retrieved sites
310 */
311 private $site_versions = [];
312
313 private static $instance;
314
315 /**
316 * Singleton. Return instance of WP_Object_Cache
317 *
318 * @return WP_Object_Cache
319 */
320 public static function instance() {
321 if ( self::$instance === null ) {
322 self::$instance = new WP_Object_Cache();
323 }
324
325 return self::$instance;
326 }
327
328 /**
329 * __clone not allowed
330 */
331 private function __clone() {
332 }
333
334 /**
335 * Direct access to __construct not allowed.
336 */
337 private function __construct() {
338 global $blog_id;
339
340 if ( ! defined( 'WP_APCU_KEY_SALT' ) ) {
341 /**
342 * Set in config if you are using some sort of shared
343 * config where ABSPATH is the same on all sites
344 */
345 define( 'WP_APCU_KEY_SALT', 'wp' );
346 }
347
348 /**
349 * define('WP_APCU_LOCAL_CACHE', false) to disable local
350 * array cache and force all cache to be returned from APCu
351 */
352 if ( ! defined( 'WP_APCU_LOCAL_CACHE' ) ) {
353 define( 'WP_APCU_LOCAL_CACHE', true );
354 }
355
356 $this->abspath = md5( ABSPATH );
357 $this->apcu_available = ( extension_loaded( 'apcu' ) && ini_get( 'apc.enabled' ) );
358 $this->multi_site = is_multisite();
359 $this->blog_prefix = $this->multi_site ? $blog_id : 1;
360 }
361
362 /**
363 * Adds data to the cache, if the cache key does not already exist.
364 *
365 * @param int|string $key The cache key to use for retrieval later
366 * @param mixed $var The data to add to the cache store
367 * @param string $group The group to add the cache to
368 * @param int $ttl When the cache data should be expired
369 *
370 * @return bool False if cache key and group already exist, true on success
371 */
372 public function add( $key, $var, $group = 'default', $ttl = 0 ) {
373 if ( wp_suspend_cache_addition() ) {
374 return false;
375 }
376
377 $key = $this->_key( $key, $group );
378
379 if ( ! $this->apcu_available || $this->_is_non_persistent_group( $group ) ) {
380 return $this->_add_np( $key, $var );
381 }
382
383 return $this->_add( $key, $var, $ttl );
384 }
385
386 /**
387 * Adds data to APCu cache, if the cache key does not already exist.
388 *
389 * @param string $key The cache key to use for retrieval later
390 * @param mixed $var The data to add to the cache store
391 * @param int $ttl When the cache data should be expired
392 *
393 * @return bool False if cache key and group already exist, true on success
394 */
395 private function _add( $key, $var, $ttl ) {
396 if ( apcu_add( $key, $var, max( (int) $ttl, 0 ) ) ) {
397 if ( WP_APCU_LOCAL_CACHE ) {
398 $this->local_cache[ $key ] = is_object( $var ) ? clone $var : $var;
399 }
400
401 return true;
402 }
403
404 return false;
405 }
406
407 /**
408 * Adds data to non persistent cache, if the cache key does not already exist.
409 *
410 * @param string $key The cache key to use for retrieval later
411 * @param mixed $var The data to add to the cache store
412 *
413 * @return bool False if cache key and group already exist, true on success
414 */
415 private function _add_np( $key, $var ) {
416 if ( $this->_exists_np( $key ) ) {
417 return false;
418 }
419
420 return $this->_set_np( $key, $var );
421 }
422
423 /**
424 * Sets the list of global groups.
425 *
426 * @param string|array $groups List of groups that are global.
427 */
428 public function add_global_groups( $groups ) {
429 foreach ( (array) $groups as $group ) {
430 $this->global_groups[ $group ] = true;
431 }
432 }
433
434 /**
435 * Sets the list of non persistent groups.
436 *
437 * @param string|array $groups List of groups that are non persistent.
438 */
439 public function add_non_persistent_groups( $groups ) {
440 foreach ( (array) $groups as $group ) {
441 $this->non_persistent_groups[ $group ] = true;
442 }
443 }
444
445 /**
446 * Decrement numeric cache item's value
447 *
448 * @param int|string $key The cache key to increment
449 * @param int $offset The amount by which to decrement the item's value. Default is 1.
450 * @param string $group The group the key is in.
451 *
452 * @return false|int False on failure, the item's new value on success.
453 */
454 public function decr( $key, $offset = 1, $group = 'default' ) {
455 $key = $this->_key( $key, $group );
456
457 if ( ! $this->apcu_available || $this->_is_non_persistent_group( $group ) ) {
458 return $this->_decr_np( $key, $offset );
459 }
460
461 return $this->_decr( $key, $offset );
462 }
463
464 /**
465 * Decrement numeric APCu cache item's value
466 *
467 * @param string $key The cache key to increment
468 * @param int $offset The amount by which to decrement the item's value. Default is 1.
469 *
470 * @return false|int False on failure, the item's new value on success.
471 */
472 private function _decr( $key, $offset ) {
473 $this->_get( $key, $success );
474 if ( ! $success ) {
475 return false;
476 }
477
478 $value = apcu_dec( $key, max( (int) $offset, 0 ) );
479 if ( $value !== false && WP_APCU_LOCAL_CACHE ) {
480 $this->local_cache[ $key ] = $value;
481 }
482
483 return $value;
484 }
485
486 /**
487 * Decrement numeric non persistent cache item's value
488 *
489 * @param string $key The cache key to increment
490 * @param int $offset The amount by which to decrement the item's value. Default is 1.
491 *
492 * @return false|int False on failure, the item's new value on success.
493 */
494 private function _decr_np( $key, $offset ) {
495 if ( ! $this->_exists_np( $key ) ) {
496 return false;
497 }
498
499 $offset = max( (int) $offset, 0 );
500 $var = $this->_get_np( $key );
501 $var = is_numeric( $var ) ? $var : 0;
502 $var -= $offset;
503
504 return $this->_set_np( $key, $var );
505 }
506
507 /**
508 * Remove the contents of the cache key in the group
509 *
510 * If the cache key does not exist in the group, then nothing will happen.
511 *
512 * @param int|string $key What the contents in the cache are called
513 * @param string $group Where the cache contents are grouped
514 * @param bool $deprecated Deprecated.
515 *
516 * @return bool False if the contents weren't deleted and true on success
517 */
518 public function delete( $key, $group = 'default', $deprecated = false ) {
519 $key = $this->_key( $key, $group );
520
521 if ( ! $this->apcu_available || $this->_is_non_persistent_group( $group ) ) {
522 return $this->_delete_np( $key );
523 }
524
525 return $this->_delete( $key );
526 }
527
528 /**
529 * Remove the contents of the APCu cache key in the group
530 *
531 * If the cache key does not exist in the group, then nothing will happen.
532 *
533 * @param string $key What the contents in the cache are called
534 *
535 * @return bool False if the contents weren't deleted and true on success
536 */
537 private function _delete( $key ) {
538 unset( $this->local_cache[ $key ] );
539
540 return apcu_delete( $key );
541 }
542
543 /**
544 * Remove the contents of the non persistent cache key in the group
545 *
546 * If the cache key does not exist in the group, then nothing will happen.
547 *
548 * @param string $key What the contents in the cache are called
549 *
550 * @return bool False if the contents weren't deleted and true on success
551 */
552 private function _delete_np( $key ) {
553 if ( array_key_exists( $key, $this->non_persistent_cache ) ) {
554 unset( $this->non_persistent_cache[ $key ] );
555
556 return true;
557 }
558
559 return false;
560 }
561
562 /**
563 * Checks if the cached non persistent key exists
564 *
565 * @param string $key What the contents in the cache are called
566 *
567 * @return bool True if cache key exists else false
568 */
569 private function _exists_np( $key ) {
570 return array_key_exists( $key, $this->non_persistent_cache );
571 }
572
573 /**
574 * Clears the object cache of all data
575 *
576 * @return bool Always returns true
577 */
578 public function flush() {
579 $this->non_persistent_cache = [];
580
581 if ( WP_APCU_LOCAL_CACHE ) {
582 $this->local_cache = [];
583 }
584
585 if ( $this->apcu_available ) {
586 apcu_clear_cache();
587 }
588
589 return true;
590 }
591
592 /**
593 * Invalidate a groups object cache
594 *
595 * @param mixed $groups A group or an array of groups to invalidate
596 *
597 * @return bool
598 */
599 public function flush_groups( $groups ) {
600 $groups = (array) $groups;
601
602 if ( empty( $groups ) ) {
603 return false;
604 }
605
606 foreach ( $groups as $group ) {
607 $version = $this->_get_group_cache_version( $group );
608 $this->_set_group_cache_version( $group, $version + 1 );
609 }
610
611 return true;
612 }
613
614 /**
615 * Invalidate a site's object cache
616 *
617 * @param mixed $sites Sites ID's that want flushing.
618 * Don't pass a site to flush current site
619 *
620 * @return bool
621 */
622 public function flush_sites( $sites ) {
623 $sites = (array) $sites;
624
625 if ( empty( $sites ) ) {
626 $sites = [ $this->blog_prefix ];
627 }
628
629 // Add global groups (site 0) to be flushed.
630 if ( ! in_array( 0, $sites, false ) ) {
631 $sites[] = 0;
632 }
633
634 foreach ( $sites as $site ) {
635 $version = $this->_get_site_cache_version( $site );
636 $this->_set_site_cache_version( $site, $version + 1 );
637 }
638
639 return true;
640 }
641
642 /**
643 * Retrieves the cache contents, if it exists
644 *
645 * The contents will be first attempted to be retrieved by searching by the
646 * key in the cache key. If the cache is hit (success) then the contents
647 * are returned.
648 *
649 * On failure, the number of cache misses will be incremented.
650 *
651 * @param int|string $key What the contents in the cache are called
652 * @param string $group Where the cache contents are grouped
653 * @param bool $force Not used.
654 * @param bool &$success
655 *
656 * @return bool|mixed False on failure to retrieve contents or the cache contents on success
657 */
658 public function get( $key, $group = 'default', $force = false, &$success = null ) {
659 $key = $this->_key( $key, $group );
660
661 if ( ! $this->apcu_available || $this->_is_non_persistent_group( $group ) ) {
662 $var = $this->_get_np( $key, $success );
663 } else {
664 $var = $this->_get( $key, $success );
665 }
666
667 if ( $success ) {
668 $this->cache_hits ++;
669 } else {
670 $this->cache_misses ++;
671 }
672
673 return $var;
674 }
675
676 /**
677 * Retrieves the APCu cache contents, if it exists
678 *
679 * @param string $key What the contents in the cache are called
680 * @param bool &$success
681 *
682 * @return bool|mixed False on failure to retrieve contents or the cache contents on success
683 */
684 private function _get( $key, &$success = null ) {
685 if ( WP_APCU_LOCAL_CACHE && array_key_exists( $key, $this->local_cache )
686 ) {
687 $success = true;
688 $var = $this->local_cache[ $key ];
689 } else {
690 $var = apcu_fetch( $key, $success );
691 if ( $success && WP_APCU_LOCAL_CACHE ) {
692 $this->local_cache[ $key ] = $var;
693 }
694 }
695
696 if ( is_object( $var ) ) {
697 $var = clone $var;
698 }
699
700 return $var;
701 }
702
703 /**
704 * Retrieves the non persistent cache contents, if it exists
705 *
706 * @param string $key What the contents in the cache are called
707 * @param bool &$success
708 *
709 * @return bool|mixed False on failure to retrieve contents or the cache contents on success
710 */
711 private function _get_np( $key, &$success = null ) {
712 if ( array_key_exists( $key, $this->non_persistent_cache ) ) {
713 $success = true;
714
715 return $this->non_persistent_cache[ $key ];
716 }
717
718 $success = false;
719
720 return false;
721 }
722
723 /**
724 * Get the cache version of a given key
725 *
726 * @param string $key
727 *
728 * @return int cache version
729 */
730 private function _get_cache_version( $key ) {
731 if ( $this->apcu_available ) {
732 $version = (int) apcu_fetch( $key );
733 } elseif ( array_key_exists( $key, $this->non_persistent_cache ) ) {
734 $version = (int) $this->non_persistent_cache[ $key ];
735 } else {
736 $version = 0;
737 }
738
739 return $version;
740 }
741
742 /**
743 * Build cache version key
744 *
745 * @param string $type Type of key, for site or group
746 * @param mixed $value the group or site id
747 *
748 * @return string The key
749 */
750 private function _get_cache_version_key( $type, $value ) {
751 return WP_APCU_KEY_SALT . ':' . $this->abspath . ':' . $type . ':' . $value;
752 }
753
754 /**
755 * Get the groups cache version
756 *
757 * @param string $group The group to get version for
758 *
759 * @return int The group cache version
760 */
761 private function _get_group_cache_version( $group ) {
762 if ( ! isset( $this->group_versions[ $group ] ) ) {
763 $this->group_versions[ $group ] = $this->_get_cache_version(
764 $this->_get_cache_version_key(
765 'GroupVersion',
766 $group
767 )
768 );
769 }
770
771 return $this->group_versions[ $group ];
772 }
773
774 /**
775 * Retrieve multiple values from cache.
776 *
777 * Gets multiple values from cache, including across multiple groups
778 *
779 * Usage: array( 'group0' => array( 'key0', 'key1', 'key2', ), 'group1' => array( 'key0' ) )
780 *
781 * @param array $groups Array of groups and keys to retrieve
782 *
783 * @return array|bool Array of cached values as
784 * array( 'group0' => array( 'key0' => 'value0', 'key1' => 'value1', 'key2' => 'value2', ) )
785 * Non-existent keys are not returned.
786 */
787 public function get_multi( $groups ) {
788 if ( empty( $groups ) || ! is_array( $groups ) ) {
789 return false;
790 }
791
792 $vars = [];
793 $success = false;
794
795 foreach ( $groups as $group => $keys ) {
796 $vars[ $group ] = [];
797
798 foreach ( $keys as $key ) {
799 $var = $this->get( $key, $group, false, $success );
800
801 if ( $success ) {
802 $vars[ $group ][ $key ] = $var;
803 }
804 }
805 }
806
807 return $vars;
808 }
809
810 /**
811 * Get the sites cache version
812 *
813 * @param int $site The site to get version for
814 *
815 * @return int The site cache version
816 */
817 private function _get_site_cache_version( $site ) {
818 if ( ! isset( $this->site_versions[ $site ] ) ) {
819 $this->site_versions[ $site ] = $this->_get_cache_version(
820 $this->_get_cache_version_key(
821 'SiteVersion',
822 $site
823 )
824 );
825 }
826
827 return $this->site_versions[ $site ];
828 }
829
830 /**
831 * Increment numeric cache item's value
832 *
833 * @param int|string $key The cache key to increment
834 * @param int $offset The amount by which to increment the item's value. Default is 1.
835 * @param string $group The group the key is in.
836 *
837 * @return false|int False on failure, the item's new value on success.
838 */
839 public function incr( $key, $offset = 1, $group = 'default' ) {
840 $key = $this->_key( $key, $group );
841
842 if ( ! $this->apcu_available || $this->_is_non_persistent_group( $group ) ) {
843 return $this->_incr_np( $key, $offset );
844 }
845
846 return $this->_incr( $key, $offset );
847 }
848
849 /**
850 * Increment numeric APCu cache item's value
851 *
852 * @param string $key The cache key to increment
853 * @param int $offset The amount by which to increment the item's value. Default is 1.
854 *
855 * @return false|int False on failure, the item's new value on success.
856 */
857 private function _incr( $key, $offset ) {
858 $this->_get( $key, $success );
859 if ( ! $success ) {
860 return false;
861 }
862
863 $value = apcu_inc( $key, max( (int) $offset, 0 ) );
864 if ( $value !== false && WP_APCU_LOCAL_CACHE ) {
865 $this->local_cache[ $key ] = $value;
866 }
867
868 return $value;
869 }
870
871 /**
872 * Increment numeric non persistent cache item's value
873 *
874 * @param string $key The cache key to increment
875 * @param int $offset The amount by which to increment the item's value. Default is 1.
876 *
877 * @return false|int False on failure, the item's new value on success.
878 */
879 private function _incr_np( $key, $offset ) {
880 if ( ! $this->_exists_np( $key ) ) {
881 return false;
882 }
883
884 $offset = max( (int) $offset, 0 );
885 $var = $this->_get_np( $key );
886 $var = is_numeric( $var ) ? $var : 0;
887 $var += $offset;
888
889 return $this->_set_np( $key, $var );
890 }
891
892 /**
893 * Checks if the given group is a non persistent group
894 *
895 * @param string $group The group to be checked
896 *
897 * @return bool True if the group is a non persistent group else false
898 */
899 private function _is_non_persistent_group( $group ) {
900 return isset( $this->non_persistent_groups[ $group ] );
901 }
902
903 /**
904 * Works out a cache key based on a given key and group
905 *
906 * @param int|string $key The key
907 * @param string $group The group
908 *
909 * @return string Returns the calculated cache key
910 */
911 private function _key( $key, $group ) {
912 if ( empty( $group ) ) {
913 $group = 'default';
914 }
915
916 $prefix = 0;
917
918 if ( ! isset( $this->global_groups[ $group ] ) ) {
919 $prefix = $this->blog_prefix;
920 }
921
922 $group_version = $this->_get_group_cache_version( $group );
923 $site_version = $this->_get_site_cache_version( $prefix );
924
925 return WP_APCU_KEY_SALT . ':' . $this->abspath . ':' . $prefix . ':' . $group . ':' . $key . ':v' . $site_version . '.' . $group_version;
926 }
927
928 /**
929 * Replace the contents in the cache, if contents already exist
930 *
931 * @param int|string $key What to call the contents in the cache
932 * @param mixed $var The contents to store in the cache
933 * @param string $group Where to group the cache contents
934 * @param int $ttl When to expire the cache contents
935 *
936 * @return bool False if not exists, true if contents were replaced
937 */
938 public function replace( $key, $var, $group = 'default', $ttl = 0 ) {
939 $key = $this->_key( $key, $group );
940
941 if ( ! $this->apcu_available || $this->_is_non_persistent_group( $group ) ) {
942 return $this->_replace_np( $key, $var );
943 }
944
945 return $this->_replace( $key, $var, $ttl );
946 }
947
948 /**
949 * Replace the contents in the APCu cache, if contents already exist
950 *
951 * @param string $key What to call the contents in the cache
952 * @param mixed $var The contents to store in the cache
953 * @param int $ttl When to expire the cache contents
954 *
955 * @return bool False if not exists, true if contents were replaced
956 */
957 private function _replace( $key, $var, $ttl ) {
958 $this->_get( $key, $success );
959 if ( $success ) {
960 return false;
961 }
962
963 return $this->_set( $key, $var, $ttl );
964 }
965
966 /**
967 * Replace the contents in the non persistent cache, if contents already exist
968 *
969 * @param string $key What to call the contents in the cache
970 * @param mixed $var The contents to store in the cache
971 *
972 * @return bool False if not exists, true if contents were replaced
973 */
974 private function _replace_np( $key, $var ) {
975 if ( ! $this->_exists_np( $key ) ) {
976 return false;
977 }
978
979 return $this->_set_np( $key, $var );
980 }
981
982 /**
983 * Sets the data contents into the cache
984 *
985 * @param int|string $key What to call the contents in the cache
986 * @param mixed $var The contents to store in the cache
987 * @param string $group Where to group the cache contents
988 * @param int $ttl When the cache data should be expired
989 *
990 * @return bool True if cache set successfully else false
991 */
992 public function set( $key, $var, $group = 'default', $ttl = 0 ) {
993 $key = $this->_key( $key, $group );
994
995 if ( ! $this->apcu_available || $this->_is_non_persistent_group( $group ) ) {
996 return $this->_set_np( $key, $var );
997 }
998
999 return $this->_set( $key, $var, $ttl );
1000 }
1001
1002 /**
1003 * Sets the data contents into the APCu cache
1004 *
1005 * @param string $key What to call the contents in the cache
1006 * @param mixed $var The contents to store in the cache
1007 * @param int $ttl When the cache data should be expired
1008 *
1009 * @return bool True if cache set successfully else false
1010 */
1011 private function _set( $key, $var, $ttl ) {
1012 if ( is_object( $var ) ) {
1013 $var = clone $var;
1014 }
1015
1016 if ( apcu_store( $key, $var, max( (int) $ttl, 0 ) ) ) {
1017 if ( WP_APCU_LOCAL_CACHE ) {
1018 $this->local_cache[ $key ] = $var;
1019 }
1020
1021 return true;
1022 }
1023
1024 return false;
1025 }
1026
1027 /**
1028 * Sets the data contents into the non persistent cache
1029 *
1030 * @param string $key What to call the contents in the cache
1031 * @param mixed $var The contents to store in the cache
1032 *
1033 * @return bool True if cache set successfully else false
1034 */
1035 private function _set_np( $key, $var ) {
1036 if ( is_object( $var ) ) {
1037 $var = clone $var;
1038 }
1039
1040 return $this->non_persistent_cache[ $key ] = $var;
1041 }
1042
1043 /**
1044 * Set the cache version for a given key
1045 *
1046 * @param string $key
1047 * @param int $version
1048 *
1049 * @return mixed
1050 */
1051 private function _set_cache_version( $key, $version ) {
1052 if ( $this->apcu_available ) {
1053 return apcu_store( $key, $version );
1054 }
1055
1056 return $this->non_persistent_cache[ $key ] = $version;
1057 }
1058
1059 /**
1060 * Set the version for a groups cache
1061 *
1062 * @param string $group
1063 * @param int $version
1064 */
1065 private function _set_group_cache_version( $group, $version ) {
1066 $this->_set_cache_version( $this->_get_cache_version_key( 'GroupVersion', $group ), $version );
1067 }
1068
1069 /**
1070 * Set the version for a sites cache
1071 *
1072 * @param int $site
1073 * @param int $version
1074 */
1075 private function _set_site_cache_version( $site, $version ) {
1076 $this->_set_cache_version( $this->_get_cache_version_key( 'SiteVersion', $site ), $version );
1077 }
1078
1079 /**
1080 * Switch the internal blog id.
1081 *
1082 * This changes the blog id used to create keys in blog specific groups.
1083 *
1084 * @param int $blog_id Blog ID
1085 */
1086 public function switch_to_blog( $blog_id ) {
1087 $this->blog_prefix = $this->multi_site ? $blog_id : 1;
1088 }
1089
1090 /**
1091 * @return string
1092 */
1093 public function getAbspath() {
1094 return $this->abspath;
1095 }
1096
1097 /**
1098 * @return bool
1099 */
1100 public function getApcuAvailable() {
1101 return $this->apcu_available;
1102 }
1103
1104 /**
1105 * @return int
1106 */
1107 public function getBlogPrefix() {
1108 return $this->blog_prefix;
1109 }
1110
1111 /**
1112 * @return int
1113 */
1114 public function getCacheHits() {
1115 return $this->cache_hits;
1116 }
1117
1118 /**
1119 * @return int
1120 */
1121 public function getCacheMisses() {
1122 return $this->cache_misses;
1123 }
1124
1125 /**
1126 * @return array
1127 */
1128 public function getGlobalGroups() {
1129 return $this->global_groups;
1130 }
1131
1132 /**
1133 * @return array
1134 */
1135 public function getGroupVersions() {
1136 return $this->group_versions;
1137 }
1138
1139 /**
1140 * @return bool
1141 */
1142 public function getMultiSite() {
1143 return $this->multi_site;
1144 }
1145
1146 /**
1147 * @return array
1148 */
1149 public function getNonPersistentCache() {
1150 return $this->non_persistent_cache;
1151 }
1152
1153 /**
1154 * @return array
1155 */
1156 public function getNonPersistentGroups() {
1157 return $this->non_persistent_groups;
1158 }
1159
1160 /**
1161 * @return array
1162 */
1163 public function getSiteVersions() {
1164 return $this->site_versions;
1165 }
1166 }