namespace = (string) $namespace; $this->defaultLifetime = $this->convertTtl($defaultLifetime); $this->miss = new \stdClass; } /** * @param bool $validation */ public function setValidation($validation) { $this->validation = (bool) $validation; } /** * @return string */ protected function getNamespace() { return $this->namespace; } /** * @return int|null */ protected function getDefaultLifetime() { return $this->defaultLifetime; } /** * @inheritdoc * @throws \Psr\SimpleCache\InvalidArgumentException|InvalidArgumentException */ public function get($key, $default = null) { $this->validateKey($key); $value = $this->doGet($key, $this->miss); return $value !== $this->miss ? $value : $default; } /** * @inheritdoc * @throws \Psr\SimpleCache\InvalidArgumentException|InvalidArgumentException */ public function set($key, $value, $ttl = null) { $this->validateKey($key); $ttl = $this->convertTtl($ttl); // If a negative or zero TTL is provided, the item MUST be deleted from the cache. return null !== $ttl && $ttl <= 0 ? $this->doDelete($key) : $this->doSet($key, $value, $ttl); } /** * @inheritdoc * @throws \Psr\SimpleCache\InvalidArgumentException|InvalidArgumentException */ public function delete($key) { $this->validateKey($key); return $this->doDelete($key); } /** * @inheritdoc */ public function clear() { return $this->doClear(); } /** * @inheritdoc * @throws \Psr\SimpleCache\InvalidArgumentException|InvalidArgumentException */ public function getMultiple($keys, $default = null) { if ($keys instanceof \Traversable) { $keys = iterator_to_array($keys, false); } elseif (!\is_array($keys)) { throw new InvalidArgumentException( sprintf( 'Cache keys must be array or Traversable, "%s" given', \is_object($keys) ? \get_class($keys) : \gettype($keys) ) ); } if (empty($keys)) { return []; } $this->validateKeys($keys); $keys = array_unique($keys); $keys = array_combine($keys, $keys); $list = $this->doGetMultiple($keys, $this->miss); // Make sure that values are returned in the same order as the keys were given. $values = []; foreach ($keys as $key) { if (!array_key_exists($key, $list) || $list[$key] === $this->miss) { $values[$key] = $default; } else { $values[$key] = $list[$key]; } } return $values; } /** * @inheritdoc * @throws \Psr\SimpleCache\InvalidArgumentException|InvalidArgumentException */ public function setMultiple($values, $ttl = null) { if ($values instanceof \Traversable) { $values = iterator_to_array($values, true); } elseif (!is_array($values)) { throw new InvalidArgumentException( sprintf( 'Cache values must be array or Traversable, "%s" given', \is_object($values) ? \get_class($values) : \gettype($values) ) ); } $keys = array_keys($values); if (empty($keys)) { return true; } $this->validateKeys($keys); $ttl = $this->convertTtl($ttl); // If a negative or zero TTL is provided, the item MUST be deleted from the cache. return null !== $ttl && $ttl <= 0 ? $this->doDeleteMultiple($keys) : $this->doSetMultiple($values, $ttl); } /** * @inheritdoc * @throws \Psr\SimpleCache\InvalidArgumentException|InvalidArgumentException */ public function deleteMultiple($keys) { if ($keys instanceof \Traversable) { $keys = iterator_to_array($keys, false); } elseif (!is_array($keys)) { throw new InvalidArgumentException( sprintf( 'Cache keys must be array or Traversable, "%s" given', \is_object($keys) ? \get_class($keys) : \gettype($keys) ) ); } if (empty($keys)) { return true; } $this->validateKeys($keys); return $this->doDeleteMultiple($keys); } /** * @inheritdoc * @throws \Psr\SimpleCache\InvalidArgumentException|InvalidArgumentException */ public function has($key) { $this->validateKey($key); return $this->doHas($key); } abstract public function doGet($key, $miss); abstract public function doSet($key, $value, $ttl); abstract public function doDelete($key); abstract public function doClear(); /** * @param array $keys * @param mixed $miss * @return array */ public function doGetMultiple($keys, $miss) { $results = []; foreach ($keys as $key) { $value = $this->doGet($key, $miss); if ($value !== $miss) { $results[$key] = $value; } } return $results; } /** * @param array $values * @param int $ttl * @return bool */ public function doSetMultiple($values, $ttl) { $success = true; foreach ($values as $key => $value) { $success = $this->doSet($key, $value, $ttl) && $success; } return $success; } /** * @param array $keys * @return bool */ public function doDeleteMultiple($keys) { $success = true; foreach ($keys as $key) { $success = $this->doDelete($key) && $success; } return $success; } abstract public function doHas($key); /** * @param string|mixed $key * @throws \Psr\SimpleCache\InvalidArgumentException|InvalidArgumentException */ protected function validateKey($key) { if (!\is_string($key)) { throw new InvalidArgumentException( sprintf( 'Cache key must be string, "%s" given', \is_object($key) ? \get_class($key) : \gettype($key) ) ); } if (!isset($key[0])) { throw new InvalidArgumentException('Cache key length must be greater than zero'); } if (\strlen($key) > 64) { throw new InvalidArgumentException( sprintf('Cache key length must be less than 65 characters, key had %s characters', \strlen($key)) ); } if (strpbrk($key, '{}()/\@:') !== false) { throw new InvalidArgumentException( sprintf('Cache key "%s" contains reserved characters {}()/\@:', $key) ); } } /** * @param array $keys * @throws \Psr\SimpleCache\InvalidArgumentException|InvalidArgumentException */ protected function validateKeys($keys) { if (!$this->validation) { return; } foreach ($keys as $key) { $this->validateKey($key); } } /** * @param null|int|\DateInterval|mixed $ttl * @return int|null * @throws \Psr\SimpleCache\InvalidArgumentException|InvalidArgumentException */ protected function convertTtl($ttl) { if ($ttl === null) { return $this->getDefaultLifetime(); } if (\is_int($ttl)) { return $ttl; } if ($ttl instanceof \DateInterval) { $ttl = (int) \DateTime::createFromFormat('U', '0')->add($ttl)->format('U'); } throw new InvalidArgumentException( sprintf( 'Expiration date must be an integer, a DateInterval or null, "%s" given', \is_object($ttl) ? \get_class($ttl) : \gettype($ttl) ) ); } }