Memcached.php 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. <?php declare (strict_types=1);
  2. namespace Sabre\Cache;
  3. use DateInterval;
  4. use DateTime;
  5. use Psr\SimpleCache\CacheInterface;
  6. use Traversable;
  7. /**
  8. * The Memcached cache uses Memcache to store values.
  9. *
  10. * This is a simple PSR-16 wrappe around memcached. To get it going, pass a
  11. * fully instantiated Memcached object to its constructor.
  12. *
  13. * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
  14. * @author Evert Pot (https://evertpot.com/)
  15. * @license http://sabre.io/license/
  16. */
  17. class Memcached implements CacheInterface {
  18. protected $memcached;
  19. /**
  20. * Creates the PSR-16 Memcache implementation.
  21. */
  22. function __construct(\Memcached $memcached) {
  23. $this->memcached = $memcached;
  24. }
  25. use MultipleTrait;
  26. /**
  27. * Fetches a value from the cache.
  28. *
  29. * @param string $key The unique key of this item in the cache.
  30. * @param mixed $default Default value to return if the key does not exist.
  31. *
  32. * @throws \Psr\SimpleCache\InvalidArgumentException
  33. * MUST be thrown if the $key string is not a legal value.
  34. * @return mixed The value of the item from the cache, or $default in case of cache miss.
  35. */
  36. function get($key, $default = null) {
  37. if (!is_string($key)) {
  38. throw new InvalidArgumentException('$key must be a string');
  39. }
  40. $result = $this->memcached->get($key);
  41. if ($result === false && $this->memcached->getResultCode() === \Memcached::RES_NOTFOUND) {
  42. return $default;
  43. }
  44. return $result;
  45. }
  46. /**
  47. * Persists data in the cache, uniquely referenced by a key with an
  48. * optional expiration TTL time.
  49. *
  50. * @param string $key The key of the item to store.
  51. * @param mixed $value The value of the item to store, must
  52. * be serializable.
  53. * @param null|int|DateInterval $ttl Optional. The TTL value of this item.
  54. * If no value is sent and the driver
  55. * supports TTL then the library may set
  56. * a default value for it or let the
  57. * driver take care of that.
  58. *
  59. * @throws \Psr\SimpleCache\InvalidArgumentException
  60. * MUST be thrown if the $key string is not a legal value.
  61. * @return bool True on success and false on failure.
  62. */
  63. function set($key, $value, $ttl = null) {
  64. if (!is_string($key)) {
  65. throw new InvalidArgumentException('$key must be a string');
  66. }
  67. if ($ttl instanceof DateInterval) {
  68. $expire = (new DateTime('now'))->add($ttl)->getTimeStamp();
  69. } elseif (is_int($ttl) || ctype_digit($ttl)) {
  70. $expire = time() + $ttl;
  71. } else {
  72. $expire = 0;
  73. }
  74. return $this->memcached->set($key, $value, $expire);
  75. }
  76. /**
  77. * Delete an item from the cache by its unique key.
  78. *
  79. * @param string $key The unique cache key of the item to delete.
  80. *
  81. * @throws \Psr\SimpleCache\InvalidArgumentException
  82. * MUST be thrown if the $key string is not a legal value.
  83. * @return bool True if the item was successfully removed. False if there was an error.
  84. */
  85. function delete($key) {
  86. if (!is_string($key)) {
  87. throw new InvalidArgumentException('$key must be a string');
  88. }
  89. return $this->memcached->delete($key);
  90. }
  91. /**
  92. * Wipes clean the entire cache's keys.
  93. *
  94. * @return bool True on success and false on failure.
  95. */
  96. function clear() {
  97. return $this->memcached->flush();
  98. }
  99. /**
  100. * Determines whether an item is present in the cache.
  101. *
  102. * NOTE: It is recommended that has() is only to be used for cache warming
  103. * type purposes and not to be used within your live applications operations
  104. * for get/set, as this method is subject to a race condition where your
  105. * has() will return true and immediately after, another script can remove
  106. * it making the state of your app out of date.
  107. *
  108. * @param string $key The cache item key.
  109. * @throws \Psr\SimpleCache\InvalidArgumentException
  110. * MUST be thrown if the $key string is not a legal value.
  111. * @return bool
  112. */
  113. function has($key) {
  114. if (!is_string($key)) {
  115. throw new InvalidArgumentException('$key must be a string');
  116. }
  117. $result = $this->memcached->get($key);
  118. if ($result === false && $this->memcached->getResultCode() === \Memcached::RES_NOTFOUND) {
  119. return false;
  120. }
  121. return true;
  122. }
  123. /**
  124. * Obtains multiple cache items by their unique keys.
  125. *
  126. * This particular implementation returns its result as a generator.
  127. *
  128. * @param iterable $keys A list of keys that can obtained in a single
  129. * operation.
  130. * @param mixed $default Default value to return for keys that do not
  131. * exist.
  132. *
  133. * @throws \Psr\SimpleCache\InvalidArgumentException
  134. * MUST be thrown if $keys is neither an array nor a Traversable,
  135. * or if any of the $keys are not a legal value.
  136. * @return iterable A list of key => value pairs. Cache keys that do not
  137. * exist or are stale will have $default as value.
  138. */
  139. function getMultiple($keys, $default = null) {
  140. if ($keys instanceof Traversable) {
  141. $keys = iterator_to_array($keys);
  142. } elseif (!is_array($keys)) {
  143. throw new InvalidArgumentException('$keys must be iterable');
  144. }
  145. $result = $this->memcached->getMulti($keys);
  146. foreach ($keys as $key) {
  147. if (!isset($result[$key])) {
  148. $result[$key] = $default;
  149. }
  150. }
  151. return $result;
  152. }
  153. /**
  154. * Persists a set of key => value pairs in the cache, with an optional TTL.
  155. *
  156. * @param iterable $values A list of key => value pairs for a
  157. * multiple-set operation.
  158. * @param null|int|DateInterval $ttl Optional. The TTL value of this
  159. * item. If no value is sent and the
  160. * driver supports TTL then the library
  161. * may set a default value for it or
  162. * let the driver take care of that.
  163. *
  164. * @throws \Psr\SimpleCache\InvalidArgumentException
  165. * MUST be thrown if $values is neither an array nor a Traversable,
  166. * or if any of the $values are not a legal value.
  167. * @return bool True on success and false on failure.
  168. */
  169. function setMultiple($values, $ttl = null) {
  170. if ($values instanceof Traversable) {
  171. $values = iterator_to_array($values);
  172. } elseif (!is_array($values)) {
  173. throw new InvalidArgumentException('$values must be iterable');
  174. }
  175. if ($ttl instanceof DateInterval) {
  176. $expire = (new DateTime('now'))->add($ttl)->getTimeStamp();
  177. } elseif (is_int($ttl) || ctype_digit($ttl)) {
  178. $expire = time() + $ttl;
  179. } else {
  180. $expire = 0;
  181. }
  182. return $this->memcached->setMulti(
  183. $values,
  184. $expire
  185. );
  186. }
  187. /**
  188. * Deletes multiple cache items in a single operation.
  189. *
  190. * @param iterable $keys A list of string-based keys to be deleted.
  191. *
  192. * @throws \Psr\SimpleCache\InvalidArgumentException
  193. * MUST be thrown if $keys is neither an array nor a Traversable,
  194. * or if any of the $keys are not a legal value.
  195. * @return bool True if the items were successfully removed. False if there
  196. * was an error.
  197. */
  198. function deleteMultiple($keys) {
  199. if ($keys instanceof Traversable) {
  200. $keys = iterator_to_array($keys);
  201. } elseif (!is_array($keys)) {
  202. throw new InvalidArgumentException('$keys must be iterable');
  203. }
  204. $this->memcached->deleteMulti($keys);
  205. }
  206. }