Açıklama Yok

class-wp-object-cache.php 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565
  1. <?php
  2. /**
  3. * Object Cache API: WP_Object_Cache class
  4. *
  5. * @package WordPress
  6. * @subpackage Cache
  7. * @since 5.4.0
  8. */
  9. /**
  10. * Core class that implements an object cache.
  11. *
  12. * The WordPress Object Cache is used to save on trips to the database. The
  13. * Object Cache stores all of the cache data to memory and makes the cache
  14. * contents available by using a key, which is used to name and later retrieve
  15. * the cache contents.
  16. *
  17. * The Object Cache can be replaced by other caching mechanisms by placing files
  18. * in the wp-content folder which is looked at in wp-settings. If that file
  19. * exists, then this file will not be included.
  20. *
  21. * @since 2.0.0
  22. */
  23. class WP_Object_Cache {
  24. /**
  25. * Holds the cached objects.
  26. *
  27. * @since 2.0.0
  28. * @var array
  29. */
  30. private $cache = array();
  31. /**
  32. * The amount of times the cache data was already stored in the cache.
  33. *
  34. * @since 2.5.0
  35. * @var int
  36. */
  37. public $cache_hits = 0;
  38. /**
  39. * Amount of times the cache did not have the request in cache.
  40. *
  41. * @since 2.0.0
  42. * @var int
  43. */
  44. public $cache_misses = 0;
  45. /**
  46. * List of global cache groups.
  47. *
  48. * @since 3.0.0
  49. * @var array
  50. */
  51. protected $global_groups = array();
  52. /**
  53. * The blog prefix to prepend to keys in non-global groups.
  54. *
  55. * @since 3.5.0
  56. * @var string
  57. */
  58. private $blog_prefix;
  59. /**
  60. * Holds the value of is_multisite().
  61. *
  62. * @since 3.5.0
  63. * @var bool
  64. */
  65. private $multisite;
  66. /**
  67. * Sets up object properties; PHP 5 style constructor.
  68. *
  69. * @since 2.0.8
  70. */
  71. public function __construct() {
  72. $this->multisite = is_multisite();
  73. $this->blog_prefix = $this->multisite ? get_current_blog_id() . ':' : '';
  74. }
  75. /**
  76. * Makes private properties readable for backward compatibility.
  77. *
  78. * @since 4.0.0
  79. *
  80. * @param string $name Property to get.
  81. * @return mixed Property.
  82. */
  83. public function __get( $name ) {
  84. return $this->$name;
  85. }
  86. /**
  87. * Makes private properties settable for backward compatibility.
  88. *
  89. * @since 4.0.0
  90. *
  91. * @param string $name Property to set.
  92. * @param mixed $value Property value.
  93. * @return mixed Newly-set property.
  94. */
  95. public function __set( $name, $value ) {
  96. return $this->$name = $value;
  97. }
  98. /**
  99. * Makes private properties checkable for backward compatibility.
  100. *
  101. * @since 4.0.0
  102. *
  103. * @param string $name Property to check if set.
  104. * @return bool Whether the property is set.
  105. */
  106. public function __isset( $name ) {
  107. return isset( $this->$name );
  108. }
  109. /**
  110. * Makes private properties un-settable for backward compatibility.
  111. *
  112. * @since 4.0.0
  113. *
  114. * @param string $name Property to unset.
  115. */
  116. public function __unset( $name ) {
  117. unset( $this->$name );
  118. }
  119. /**
  120. * Serves as a utility function to determine whether a key exists in the cache.
  121. *
  122. * @since 3.4.0
  123. *
  124. * @param int|string $key Cache key to check for existence.
  125. * @param string $group Cache group for the key existence check.
  126. * @return bool Whether the key exists in the cache for the given group.
  127. */
  128. protected function _exists( $key, $group ) {
  129. return isset( $this->cache[ $group ] ) && ( isset( $this->cache[ $group ][ $key ] ) || array_key_exists( $key, $this->cache[ $group ] ) );
  130. }
  131. /**
  132. * Adds data to the cache if it doesn't already exist.
  133. *
  134. * @since 2.0.0
  135. *
  136. * @uses WP_Object_Cache::_exists() Checks to see if the cache already has data.
  137. * @uses WP_Object_Cache::set() Sets the data after the checking the cache
  138. * contents existence.
  139. *
  140. * @param int|string $key What to call the contents in the cache.
  141. * @param mixed $data The contents to store in the cache.
  142. * @param string $group Optional. Where to group the cache contents. Default 'default'.
  143. * @param int $expire Optional. When to expire the cache contents, in seconds.
  144. * Default 0 (no expiration).
  145. * @return bool True on success, false if cache key and group already exist.
  146. */
  147. public function add( $key, $data, $group = 'default', $expire = 0 ) {
  148. if ( wp_suspend_cache_addition() ) {
  149. return false;
  150. }
  151. if ( empty( $group ) ) {
  152. $group = 'default';
  153. }
  154. $id = $key;
  155. if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) ) {
  156. $id = $this->blog_prefix . $key;
  157. }
  158. if ( $this->_exists( $id, $group ) ) {
  159. return false;
  160. }
  161. return $this->set( $key, $data, $group, (int) $expire );
  162. }
  163. /**
  164. * Adds multiple values to the cache in one call.
  165. *
  166. * @since 6.0.0
  167. *
  168. * @param array $data Array of keys and values to be added.
  169. * @param string $group Optional. Where the cache contents are grouped. Default empty.
  170. * @param int $expire Optional. When to expire the cache contents, in seconds.
  171. * Default 0 (no expiration).
  172. * @return bool[] Array of return values, grouped by key. Each value is either
  173. * true on success, or false if cache key and group already exist.
  174. */
  175. public function add_multiple( array $data, $group = '', $expire = 0 ) {
  176. $values = array();
  177. foreach ( $data as $key => $value ) {
  178. $values[ $key ] = $this->add( $key, $value, $group, $expire );
  179. }
  180. return $values;
  181. }
  182. /**
  183. * Replaces the contents in the cache, if contents already exist.
  184. *
  185. * @since 2.0.0
  186. *
  187. * @see WP_Object_Cache::set()
  188. *
  189. * @param int|string $key What to call the contents in the cache.
  190. * @param mixed $data The contents to store in the cache.
  191. * @param string $group Optional. Where to group the cache contents. Default 'default'.
  192. * @param int $expire Optional. When to expire the cache contents, in seconds.
  193. * Default 0 (no expiration).
  194. * @return bool True if contents were replaced, false if original value does not exist.
  195. */
  196. public function replace( $key, $data, $group = 'default', $expire = 0 ) {
  197. if ( empty( $group ) ) {
  198. $group = 'default';
  199. }
  200. $id = $key;
  201. if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) ) {
  202. $id = $this->blog_prefix . $key;
  203. }
  204. if ( ! $this->_exists( $id, $group ) ) {
  205. return false;
  206. }
  207. return $this->set( $key, $data, $group, (int) $expire );
  208. }
  209. /**
  210. * Sets the data contents into the cache.
  211. *
  212. * The cache contents are grouped by the $group parameter followed by the
  213. * $key. This allows for duplicate IDs in unique groups. Therefore, naming of
  214. * the group should be used with care and should follow normal function
  215. * naming guidelines outside of core WordPress usage.
  216. *
  217. * The $expire parameter is not used, because the cache will automatically
  218. * expire for each time a page is accessed and PHP finishes. The method is
  219. * more for cache plugins which use files.
  220. *
  221. * @since 2.0.0
  222. *
  223. * @param int|string $key What to call the contents in the cache.
  224. * @param mixed $data The contents to store in the cache.
  225. * @param string $group Optional. Where to group the cache contents. Default 'default'.
  226. * @param int $expire Optional. Not used.
  227. * @return true Always returns true.
  228. */
  229. public function set( $key, $data, $group = 'default', $expire = 0 ) {
  230. if ( empty( $group ) ) {
  231. $group = 'default';
  232. }
  233. if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) ) {
  234. $key = $this->blog_prefix . $key;
  235. }
  236. if ( is_object( $data ) ) {
  237. $data = clone $data;
  238. }
  239. $this->cache[ $group ][ $key ] = $data;
  240. return true;
  241. }
  242. /**
  243. * Sets multiple values to the cache in one call.
  244. *
  245. * @since 6.0.0
  246. *
  247. * @param array $data Array of key and value to be set.
  248. * @param string $group Optional. Where the cache contents are grouped. Default empty.
  249. * @param int $expire Optional. When to expire the cache contents, in seconds.
  250. * Default 0 (no expiration).
  251. * @return bool[] Array of return values, grouped by key. Each value is always true.
  252. */
  253. public function set_multiple( array $data, $group = '', $expire = 0 ) {
  254. $values = array();
  255. foreach ( $data as $key => $value ) {
  256. $values[ $key ] = $this->set( $key, $value, $group, $expire );
  257. }
  258. return $values;
  259. }
  260. /**
  261. * Retrieves the cache contents, if it exists.
  262. *
  263. * The contents will be first attempted to be retrieved by searching by the
  264. * key in the cache group. If the cache is hit (success) then the contents
  265. * are returned.
  266. *
  267. * On failure, the number of cache misses will be incremented.
  268. *
  269. * @since 2.0.0
  270. *
  271. * @param int|string $key The key under which the cache contents are stored.
  272. * @param string $group Optional. Where the cache contents are grouped. Default 'default'.
  273. * @param bool $force Optional. Unused. Whether to force an update of the local cache
  274. * from the persistent cache. Default false.
  275. * @param bool $found Optional. Whether the key was found in the cache (passed by reference).
  276. * Disambiguates a return of false, a storable value. Default null.
  277. * @return mixed|false The cache contents on success, false on failure to retrieve contents.
  278. */
  279. public function get( $key, $group = 'default', $force = false, &$found = null ) {
  280. if ( empty( $group ) ) {
  281. $group = 'default';
  282. }
  283. if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) ) {
  284. $key = $this->blog_prefix . $key;
  285. }
  286. if ( $this->_exists( $key, $group ) ) {
  287. $found = true;
  288. $this->cache_hits += 1;
  289. if ( is_object( $this->cache[ $group ][ $key ] ) ) {
  290. return clone $this->cache[ $group ][ $key ];
  291. } else {
  292. return $this->cache[ $group ][ $key ];
  293. }
  294. }
  295. $found = false;
  296. $this->cache_misses += 1;
  297. return false;
  298. }
  299. /**
  300. * Retrieves multiple values from the cache in one call.
  301. *
  302. * @since 5.5.0
  303. *
  304. * @param array $keys Array of keys under which the cache contents are stored.
  305. * @param string $group Optional. Where the cache contents are grouped. Default 'default'.
  306. * @param bool $force Optional. Whether to force an update of the local cache
  307. * from the persistent cache. Default false.
  308. * @return array Array of return values, grouped by key. Each value is either
  309. * the cache contents on success, or false on failure.
  310. */
  311. public function get_multiple( $keys, $group = 'default', $force = false ) {
  312. $values = array();
  313. foreach ( $keys as $key ) {
  314. $values[ $key ] = $this->get( $key, $group, $force );
  315. }
  316. return $values;
  317. }
  318. /**
  319. * Removes the contents of the cache key in the group.
  320. *
  321. * If the cache key does not exist in the group, then nothing will happen.
  322. *
  323. * @since 2.0.0
  324. *
  325. * @param int|string $key What the contents in the cache are called.
  326. * @param string $group Optional. Where the cache contents are grouped. Default 'default'.
  327. * @param bool $deprecated Optional. Unused. Default false.
  328. * @return bool True on success, false if the contents were not deleted.
  329. */
  330. public function delete( $key, $group = 'default', $deprecated = false ) {
  331. if ( empty( $group ) ) {
  332. $group = 'default';
  333. }
  334. if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) ) {
  335. $key = $this->blog_prefix . $key;
  336. }
  337. if ( ! $this->_exists( $key, $group ) ) {
  338. return false;
  339. }
  340. unset( $this->cache[ $group ][ $key ] );
  341. return true;
  342. }
  343. /**
  344. * Deletes multiple values from the cache in one call.
  345. *
  346. * @since 6.0.0
  347. *
  348. * @param array $keys Array of keys to be deleted.
  349. * @param string $group Optional. Where the cache contents are grouped. Default empty.
  350. * @return bool[] Array of return values, grouped by key. Each value is either
  351. * true on success, or false if the contents were not deleted.
  352. */
  353. public function delete_multiple( array $keys, $group = '' ) {
  354. $values = array();
  355. foreach ( $keys as $key ) {
  356. $values[ $key ] = $this->delete( $key, $group );
  357. }
  358. return $values;
  359. }
  360. /**
  361. * Increments numeric cache item's value.
  362. *
  363. * @since 3.3.0
  364. *
  365. * @param int|string $key The cache key to increment.
  366. * @param int $offset Optional. The amount by which to increment the item's value.
  367. * Default 1.
  368. * @param string $group Optional. The group the key is in. Default 'default'.
  369. * @return int|false The item's new value on success, false on failure.
  370. */
  371. public function incr( $key, $offset = 1, $group = 'default' ) {
  372. if ( empty( $group ) ) {
  373. $group = 'default';
  374. }
  375. if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) ) {
  376. $key = $this->blog_prefix . $key;
  377. }
  378. if ( ! $this->_exists( $key, $group ) ) {
  379. return false;
  380. }
  381. if ( ! is_numeric( $this->cache[ $group ][ $key ] ) ) {
  382. $this->cache[ $group ][ $key ] = 0;
  383. }
  384. $offset = (int) $offset;
  385. $this->cache[ $group ][ $key ] += $offset;
  386. if ( $this->cache[ $group ][ $key ] < 0 ) {
  387. $this->cache[ $group ][ $key ] = 0;
  388. }
  389. return $this->cache[ $group ][ $key ];
  390. }
  391. /**
  392. * Decrements numeric cache item's value.
  393. *
  394. * @since 3.3.0
  395. *
  396. * @param int|string $key The cache key to decrement.
  397. * @param int $offset Optional. The amount by which to decrement the item's value.
  398. * Default 1.
  399. * @param string $group Optional. The group the key is in. Default 'default'.
  400. * @return int|false The item's new value on success, false on failure.
  401. */
  402. public function decr( $key, $offset = 1, $group = 'default' ) {
  403. if ( empty( $group ) ) {
  404. $group = 'default';
  405. }
  406. if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) ) {
  407. $key = $this->blog_prefix . $key;
  408. }
  409. if ( ! $this->_exists( $key, $group ) ) {
  410. return false;
  411. }
  412. if ( ! is_numeric( $this->cache[ $group ][ $key ] ) ) {
  413. $this->cache[ $group ][ $key ] = 0;
  414. }
  415. $offset = (int) $offset;
  416. $this->cache[ $group ][ $key ] -= $offset;
  417. if ( $this->cache[ $group ][ $key ] < 0 ) {
  418. $this->cache[ $group ][ $key ] = 0;
  419. }
  420. return $this->cache[ $group ][ $key ];
  421. }
  422. /**
  423. * Clears the object cache of all data.
  424. *
  425. * @since 2.0.0
  426. *
  427. * @return true Always returns true.
  428. */
  429. public function flush() {
  430. $this->cache = array();
  431. return true;
  432. }
  433. /**
  434. * Sets the list of global cache groups.
  435. *
  436. * @since 3.0.0
  437. *
  438. * @param string|string[] $groups List of groups that are global.
  439. */
  440. public function add_global_groups( $groups ) {
  441. $groups = (array) $groups;
  442. $groups = array_fill_keys( $groups, true );
  443. $this->global_groups = array_merge( $this->global_groups, $groups );
  444. }
  445. /**
  446. * Switches the internal blog ID.
  447. *
  448. * This changes the blog ID used to create keys in blog specific groups.
  449. *
  450. * @since 3.5.0
  451. *
  452. * @param int $blog_id Blog ID.
  453. */
  454. public function switch_to_blog( $blog_id ) {
  455. $blog_id = (int) $blog_id;
  456. $this->blog_prefix = $this->multisite ? $blog_id . ':' : '';
  457. }
  458. /**
  459. * Resets cache keys.
  460. *
  461. * @since 3.0.0
  462. *
  463. * @deprecated 3.5.0 Use WP_Object_Cache::switch_to_blog()
  464. * @see switch_to_blog()
  465. */
  466. public function reset() {
  467. _deprecated_function( __FUNCTION__, '3.5.0', 'WP_Object_Cache::switch_to_blog()' );
  468. // Clear out non-global caches since the blog ID has changed.
  469. foreach ( array_keys( $this->cache ) as $group ) {
  470. if ( ! isset( $this->global_groups[ $group ] ) ) {
  471. unset( $this->cache[ $group ] );
  472. }
  473. }
  474. }
  475. /**
  476. * Echoes the stats of the caching.
  477. *
  478. * Gives the cache hits, and cache misses. Also prints every cached group,
  479. * key and the data.
  480. *
  481. * @since 2.0.0
  482. */
  483. public function stats() {
  484. echo '<p>';
  485. echo "<strong>Cache Hits:</strong> {$this->cache_hits}<br />";
  486. echo "<strong>Cache Misses:</strong> {$this->cache_misses}<br />";
  487. echo '</p>';
  488. echo '<ul>';
  489. foreach ( $this->cache as $group => $cache ) {
  490. echo '<li><strong>Group:</strong> ' . esc_html( $group ) . ' - ( ' . number_format( strlen( serialize( $cache ) ) / KB_IN_BYTES, 2 ) . 'k )</li>';
  491. }
  492. echo '</ul>';
  493. }
  494. }