WordPress.org

Make WordPress Core

Ticket #15304: object-cache.php

File object-cache.php, 13.3 KB (added by mrasnika, 5 years ago)
Line 
1<?php 
2
3/**
4* File-based caching
5*
6* @author Kaloyan K. Tsvetkov <kaloyan@kaloyan.info>
7* @license GPLv2
8*
9* @package WordPress
10* @subpackage Cache
11*/
12
13/**
14 * Adds data to the cache, if the cache key doesn't aleady exist.
15 *
16 * @since 2.0.0
17 * @uses $wp_object_cache Object Cache Class
18 * @see WP_Object_Cache::add()
19 *
20 * @param int|string $key The cache ID to use for retrieval later
21 * @param mixed $data The data to add to the cache store
22 * @param string $flag The group to add the cache to
23 * @param int $expire When the cache data should be expired
24 * @return unknown
25 */
26function wp_cache_add($key, $data, $flag = '', $expire = 0) {
27        global $wp_object_cache;
28
29        return $wp_object_cache->add($key, $data, $flag, $expire);
30}
31
32/**
33 * Closes the cache.
34 *
35 * This function has ceased to do anything since WordPress 2.5. The
36 * functionality was removed along with the rest of the persistant cache. This
37 * does not mean that plugins can't implement this function when they need to
38 * make sure that the cache is cleaned up after WordPress no longer needs it.
39 *
40 * @since 2.0.0
41 *
42 * @return bool Always returns True
43 */
44function wp_cache_close() {
45        return true;
46}
47
48/**
49 * Removes the cache contents matching ID and flag.
50 *
51 * @since 2.0.0
52 * @uses $wp_object_cache Object Cache Class
53 * @see WP_Object_Cache::delete()
54 *
55 * @param int|string $id What the contents in the cache are called
56 * @param string $flag Where the cache contents are grouped
57 * @return bool True on successful removal, false on failure
58 */
59function wp_cache_delete($id, $flag = '') {
60        global $wp_object_cache;
61
62        return $wp_object_cache->delete($id, $flag);
63}
64
65/**
66 * Removes all cache items.
67 *
68 * @since 2.0.0
69 * @uses $wp_object_cache Object Cache Class
70 * @see WP_Object_Cache::flush()
71 *
72 * @return bool Always returns true
73 */
74function wp_cache_flush() {
75        global $wp_object_cache;
76
77        return $wp_object_cache->flush();
78}
79
80/**
81 * Retrieves the cache contents from the cache by ID and flag.
82 *
83 * @since 2.0.0
84 * @uses $wp_object_cache Object Cache Class
85 * @see WP_Object_Cache::get()
86 *
87 * @param int|string $id What the contents in the cache are called
88 * @param string $flag Where the cache contents are grouped
89 * @return bool|mixed False on failure to retrieve contents or the cache
90 *              contents on success
91 */
92function wp_cache_get($id, $flag = '') {
93        global $wp_object_cache;
94
95        return $wp_object_cache->get($id, $flag);
96}
97
98/**
99 * Sets up Object Cache Global and assigns it.
100 *
101 * @since 2.0.0
102 * @global WP_Object_Cache $wp_object_cache WordPress Object Cache
103 */
104function wp_cache_init() {
105        $GLOBALS['wp_object_cache'] =& new WP_Object_Cache();
106}
107
108/**
109 * Replaces the contents of the cache with new data.
110 *
111 * @since 2.0.0
112 * @uses $wp_object_cache Object Cache Class
113 * @see WP_Object_Cache::replace()
114 *
115 * @param int|string $id What to call the contents in the cache
116 * @param mixed $data The contents to store in the cache
117 * @param string $flag Where to group the cache contents
118 * @param int $expire When to expire the cache contents
119 * @return bool False if cache ID and group already exists, true on success
120 */
121function wp_cache_replace($key, $data, $flag = '', $expire = 0) {
122        global $wp_object_cache;
123
124        return $wp_object_cache->replace($key, $data, $flag, $expire);
125}
126
127/**
128 * Saves the data to the cache.
129 *
130 * @since 2.0
131 * @uses $wp_object_cache Object Cache Class
132 * @see WP_Object_Cache::set()
133 *
134 * @param int|string $id What to call the contents in the cache
135 * @param mixed $data The contents to store in the cache
136 * @param string $flag Where to group the cache contents
137 * @param int $expire When to expire the cache contents
138 * @return bool False if cache ID and group already exists, true on success
139 */
140function wp_cache_set($key, $data, $flag = '', $expire = 0) {
141        global $wp_object_cache;
142
143        return $wp_object_cache->set($key, $data, $flag, $expire);
144}
145
146/**
147 * Adds a group or set of groups to the list of global groups.
148 *
149 * @since 2.6.0
150 *
151 * @param string|array $groups A group or an array of groups to add
152 */
153function wp_cache_add_global_groups( $groups ) {
154        global $wp_object_cache;
155
156        return $wp_object_cache->add_global_groups($groups);
157}
158
159/**
160 * Adds a group or set of groups to the list of non-persistent groups.
161 *
162 * @since 2.6.0
163 *
164 * @param string|array $groups A group or an array of groups to add
165 */
166function wp_cache_add_non_persistent_groups( $groups ) {
167        // Default cache doesn't persist so nothing to do here.
168        return;
169}
170
171/**
172 * Reset internal cache keys and structures.  If the cache backend uses global blog or site IDs as part of its cache keys,
173 * this function instructs the backend to reset those keys and perform any cleanup since blog or site IDs have changed since cache init.
174 *
175 * @since 2.6.0
176 *
177 * @param string|array $groups A group or an array of groups to add
178 */
179function wp_cache_reset() {
180        global $wp_object_cache;
181
182        return $wp_object_cache->reset();
183}
184
185/**
186 * WordPress Object Cache
187 *
188 * The WordPress Object Cache is used to save on trips to the database. The
189 * Object Cache stores all of the cache data to memory and makes the cache
190 * contents available by using a key, which is used to name and later retrieve
191 * the cache contents.
192 *
193 * @package WordPress
194 * @subpackage Cache
195 */
196class WP_Object_Cache {
197
198        /**
199         * Holds the cached objects
200         *
201         * @var array
202         * @access private
203         * @since 2.0.0
204         */
205        var $cache = array ();
206
207
208        /**
209         * The amount of times the cache data was already stored in the cache.
210         *
211         * @since 2.5.0
212         * @access private
213         * @var int
214         */
215        var $cache_hits = 0;
216
217        /**
218         * Amount of times the cache did not have the request in cache
219         *
220         * @var int
221         * @access public
222         * @since 2.0.0
223         */
224        var $cache_misses = 0;
225
226        /**
227         * List of global groups
228         *
229         * @var array
230         * @access protected
231         * @since 3.0.0
232         */
233        var $global_groups = array();
234
235        /**
236         * Name of the cache file
237         *
238         * @var string
239         * @access protected
240         */
241        var $cache_filename;
242
243        /**
244         * Whether the cache needs to be updated
245         *
246         * @var boolean
247         * @access protected
248         */
249        var $cache_update = false;
250
251        /**
252         * Adds data to the cache if it doesn't already exist.
253         *
254         * @uses WP_Object_Cache::get Checks to see if the cache already has data.
255         * @uses WP_Object_Cache::set Sets the data after the checking the cache
256         *              contents existance.
257         *
258         * @param int|string $id What to call the contents in the cache
259         * @param mixed $data The contents to store in the cache
260         * @param string $group Where to group the cache contents
261         * @param int $expire When to expire the cache contents
262         * @return bool False if cache ID and group already exists, true on success
263         */
264        function add( $id, $data, $group = 'default', $expire = '' ) {
265                if ( empty ($group) )
266                        $group = 'default';
267
268                if (false !== $this->get($id, $group))
269                        return false;
270
271                return $this->set($id, $data, $group, $expire);
272        }
273
274        /**
275         * Sets the list of global groups.
276         *
277         * @since 3.0.0
278         *
279         * @param array $groups List of groups that are global.
280         */
281        function add_global_groups( $groups ) {
282                $groups = (array) $groups;
283
284                $this->global_groups = array_merge($this->global_groups, $groups);
285                $this->global_groups = array_unique($this->global_groups);
286        }
287
288        /**
289         * Remove the contents of the cache ID in the group
290         *
291         * If the cache ID does not exist in the group and $force parameter is set
292         * to false, then nothing will happen. The $force parameter is set to false
293         * by default.
294         *
295         * @param int|string $id What the contents in the cache are called
296         * @param string $group Where the cache contents are grouped
297         * @param bool $force Optional. Whether to force the unsetting of the cache
298         *              ID in the group
299         * @return bool False if the contents weren't deleted and true on success
300         */
301        function delete($id, $group = 'default', $force = false) {
302                if (empty ($group))
303                        $group = 'default';
304
305                if (!$force && false === $this->get($id, $group))
306                        return false;
307
308                unset ($this->cache[$group][$id]);
309               
310                $this->cache_update = true;
311                return true;
312        }
313
314        /**
315         * Clears the object cache of all data
316         *
317         * @since 2.0.0
318         *
319         * @return bool Always returns true
320         */
321        function flush() {
322                $this->cache = array ();
323                $this->cache_update = true;
324                return true;
325                }
326
327        /**
328         * Retrieves the cache contents, if it exists
329         *
330         * The contents will be first attempted to be retrieved by searching by the
331         * ID in the cache group. If the cache is hit (success) then the contents
332         * are returned.
333         *
334         * @param int|string $id What the contents in the cache are called
335         * @param string $group Where the cache contents are grouped
336         * @return bool|mixed False on failure to retrieve contents or the cache
337         *              contents on success
338         */
339        function get($id, $group = 'default') {
340                if ( empty ($group) )
341                        $group = 'default';
342
343                if ( isset ($this->cache[$group][$id]) ) {
344                        $this->cache_hits += 1;
345                        if ( is_object($this->cache[$group][$id]) )
346                                return wp_clone($this->cache[$group][$id]);
347                        else
348                                return $this->cache[$group][$id];
349                }
350
351                $this->cache_misses += 1;
352                return false;
353        }
354
355        /**
356         * Replace the contents in the cache, if contents already exist
357         *
358         * @since 2.0.0
359         * @see WP_Object_Cache::set()
360         *
361         * @param int|string $id What to call the contents in the cache
362         * @param mixed $data The contents to store in the cache
363         * @param string $group Where to group the cache contents
364         * @param int $expire When to expire the cache contents
365         * @return bool False if not exists, true if contents were replaced
366         */
367        function replace($id, $data, $group = 'default', $expire = '') {
368                if (empty ($group))
369                        $group = 'default';
370
371                if ( false === $this->get($id, $group) )
372                        return false;
373
374                return $this->set($id, $data, $group, $expire);
375        }
376
377        /**
378         * Reset keys
379         *
380         * @since 3.0.0
381         */
382        function reset() {
383                // Clear out non-global caches since the blog ID has changed.
384                foreach ( array_keys($this->cache) as $group ) {
385                        if ( !in_array($group, $this->global_groups) )
386                                unset($this->cache[$group]);
387                $this->cache_update = true;
388                }
389        }
390
391        /**
392         * Sets the data contents into the cache
393         *
394         * The cache contents is grouped by the $group parameter followed by the
395         * $id. This allows for duplicate ids in unique groups. Therefore, naming of
396         * the group should be used with care and should follow normal function
397         * naming guidelines outside of core WordPress usage.
398         *
399         * The $expire parameter is not used, because the cache will automatically
400         * expire for each time a page is accessed and PHP finishes. The method is
401         * more for cache plugins which use files.
402         *
403         * @since 2.0.0
404         *
405         * @param int|string $id What to call the contents in the cache
406         * @param mixed $data The contents to store in the cache
407         * @param string $group Where to group the cache contents
408         * @param int $expire Not Used
409         * @return bool Always returns true
410         */
411        function set($id, $data, $group = 'default', $expire = '') {
412
413                if ( empty ($group) )
414                        $group = 'default';
415
416                if ( NULL === $data )
417                        $data = '';
418
419                // if you are setting the same value as the
420                // one in the cache then get the fuck out!
421                //
422                if (isset($this->cache[$group][$id]) && $data === $this->cache[$group][$id]) {
423                        return true;
424                        }
425
426                if ( is_object($data) ) {
427                        $data = wp_clone($data);
428                       
429                        if ('stdClass' == get_class($data)) {
430                                $data = stdKlass::prepare($data);
431                                }
432                        }
433
434                $this->cache[$group][$id] = $data;
435                $this->cache_update = true;
436
437                return true;
438        }
439
440        /**
441         * Echoes the stats of the caching.
442         *
443         * Gives the cache hits, and cache misses. Also prints every cached group,
444         * key and the data.
445         *
446         * @since 2.0.0
447         */
448        function stats() {
449                echo "<p>";
450                echo "<strong>Cache Hits:</strong> {$this->cache_hits}<br />";
451                echo "<strong>Cache Misses:</strong> {$this->cache_misses}<br />";
452                echo "</p>";
453
454                foreach ($this->cache as $group => $cache) {
455                        echo "<p>";
456                        echo "<strong>Group:</strong> $group<br />";
457                        echo "<strong>Cache:</strong>";
458                        echo "<pre>";
459                        print_r($cache);
460                        echo "</pre>";
461                }
462        }
463
464        /**
465         * PHP4 constructor; Calls PHP 5 style constructor
466         *
467         * @since 2.0.0
468         *
469         * @return WP_Object_Cache
470         */
471        function WP_Object_Cache() {
472                register_shutdown_function(array(&$this, '__destruct'));               
473                return $this->__construct();
474        }
475
476        /**
477         * Sets up object properties; PHP 5 style constructor
478         *
479         * @since 2.0.8
480         * @return null|WP_Object_Cache If cache is disabled, returns null.
481         */
482        function __construct() {
483
484                $this->cache_filename = WP_CONTENT_DIR . '/cache.' . DB_NAME . '.php';
485
486                ob_start();
487                include($this->cache_filename);
488                ob_end_clean();
489
490                if (isset($a) && is_array($a)) {
491                        $this->cache = $a;
492                        }
493        }
494
495        /**
496         * Will save the object cache before object is completely destroyed.
497         *
498         * Called upon object destruction, which should be when PHP ends.
499         *
500         * @return bool True value. Won't be used by PHP
501         */
502        function __destruct() {
503               
504                // no updates, get out
505                //
506                if (!$this->cache_update) {
507                        return true;
508                        }
509               
510                if ($fp = @fopen($this->cache_filename, 'w')) {
511                        flock($fp, LOCK_EX);
512                        fwrite($fp, '<?php $a = ' . var_export($this->cache, true). '; ');
513                        flock($fp, LOCK_UN);
514                        fclose($fp);
515                        }
516               
517                return true;
518        }
519}
520
521/**
522*/
523Class stdKlass {
524
525        /**
526        */
527        function prepare(&$data) {
528               
529                $r = ($is_object = is_object($data))
530                        ? new stdKlass
531                        : array();
532               
533                foreach ($data as $k => $v) {
534                        if ($is_object) {
535                                $b =& $r->$k;
536                                } else {
537                                $b =& $r[$k];
538                                }
539
540                        $b = is_scalar($v)
541                                ? $v
542                                : stdKlass::prepare($v);
543                        }
544
545                return $r;
546                }
547
548        /**
549        */     
550        function __set_state($data) {
551                return (object) $data;
552                }
553       
554        }