Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
minor #31760 [Cache] remove deprecated PSR-16 implementations et al. …
…(nicolas-grekas)

This PR was merged into the 5.0-dev branch.

Discussion
----------

[Cache] remove deprecated PSR-16 implementations et al.

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | no
| BC breaks?    | yes
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | -
| License       | MIT
| Doc PR        | -

\o/

(use `Psr16Cache` instead)

Commits
-------

38a67f8 [Cache] remove deprecated PSR-16 implementations et al.
  • Loading branch information
nicolas-grekas committed Jun 2, 2019
2 parents 090cf32 + 38a67f8 commit 4a437ab
Show file tree
Hide file tree
Showing 59 changed files with 1,611 additions and 4,905 deletions.
103 changes: 99 additions & 4 deletions src/Symfony/Component/Cache/Adapter/ApcuAdapter.php
Expand Up @@ -11,17 +11,112 @@

namespace Symfony\Component\Cache\Adapter;

use Symfony\Component\Cache\Traits\ApcuTrait;
use Symfony\Component\Cache\CacheItem;
use Symfony\Component\Cache\Exception\CacheException;

/**
* @author Nicolas Grekas <p@tchwork.com>
*/
class ApcuAdapter extends AbstractAdapter
{
use ApcuTrait;

/**
* @throws CacheException if APCu is not enabled
*/
public function __construct(string $namespace = '', int $defaultLifetime = 0, string $version = null)
{
$this->init($namespace, $defaultLifetime, $version);
if (!static::isSupported()) {
throw new CacheException('APCu is not enabled');
}
if ('cli' === \PHP_SAPI) {
ini_set('apc.use_request_time', 0);
}
parent::__construct($namespace, $defaultLifetime);

if (null !== $version) {
CacheItem::validateKey($version);

if (!apcu_exists($version.'@'.$namespace)) {
$this->doClear($namespace);
apcu_add($version.'@'.$namespace, null);
}
}
}

public static function isSupported()
{
return \function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN);
}

/**
* {@inheritdoc}
*/
protected function doFetch(array $ids)
{
$unserializeCallbackHandler = ini_set('unserialize_callback_func', __CLASS__.'::handleUnserializeCallback');
try {
$values = [];
foreach (apcu_fetch($ids, $ok) ?: [] as $k => $v) {
if (null !== $v || $ok) {
$values[$k] = $v;
}
}

return $values;
} catch (\Error $e) {
throw new \ErrorException($e->getMessage(), $e->getCode(), E_ERROR, $e->getFile(), $e->getLine());
} finally {
ini_set('unserialize_callback_func', $unserializeCallbackHandler);
}
}

/**
* {@inheritdoc}
*/
protected function doHave($id)
{
return apcu_exists($id);
}

/**
* {@inheritdoc}
*/
protected function doClear($namespace)
{
return isset($namespace[0]) && class_exists('APCuIterator', false) && ('cli' !== \PHP_SAPI || filter_var(ini_get('apc.enable_cli'), FILTER_VALIDATE_BOOLEAN))
? apcu_delete(new \APCuIterator(sprintf('/^%s/', preg_quote($namespace, '/')), APC_ITER_KEY))
: apcu_clear_cache();
}

/**
* {@inheritdoc}
*/
protected function doDelete(array $ids)
{
foreach ($ids as $id) {
apcu_delete($id);
}

return true;
}

/**
* {@inheritdoc}
*/
protected function doSave(array $values, $lifetime)
{
try {
if (false === $failures = apcu_store($values, null, $lifetime)) {
$failures = $values;
}

return array_keys($failures);
} catch (\Throwable $e) {
if (1 === \count($values)) {
// Workaround https://github.com/krakjoe/apcu/issues/170
apcu_delete(key($values));
}

throw $e;
}
}
}
147 changes: 143 additions & 4 deletions src/Symfony/Component/Cache/Adapter/ArrayAdapter.php
Expand Up @@ -13,18 +13,21 @@

use Psr\Cache\CacheItemInterface;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerAwareTrait;
use Symfony\Component\Cache\CacheItem;
use Symfony\Component\Cache\ResettableInterface;
use Symfony\Component\Cache\Traits\ArrayTrait;
use Symfony\Contracts\Cache\CacheInterface;

/**
* @author Nicolas Grekas <p@tchwork.com>
*/
class ArrayAdapter implements AdapterInterface, CacheInterface, LoggerAwareInterface, ResettableInterface
{
use ArrayTrait;
use LoggerAwareTrait;

private $storeSerialized;
private $values = [];
private $expiries = [];
private $createCacheItem;

/**
Expand Down Expand Up @@ -65,6 +68,27 @@ public function get(string $key, callable $callback, float $beta = null, array &
return $item->get();
}

/**
* {@inheritdoc}
*/
public function delete(string $key): bool
{
return $this->deleteItem($key);
}

/**
* {@inheritdoc}
*/
public function hasItem($key)
{
if (\is_string($key) && isset($this->expiries[$key]) && $this->expiries[$key] > microtime(true)) {
return true;
}
CacheItem::validateKey($key);

return isset($this->expiries[$key]) && !$this->deleteItem($key);
}

/**
* {@inheritdoc}
*/
Expand Down Expand Up @@ -94,6 +118,19 @@ public function getItems(array $keys = [])
return $this->generateItems($keys, microtime(true), $this->createCacheItem);
}

/**
* {@inheritdoc}
*/
public function deleteItem($key)
{
if (!\is_string($key) || !isset($this->expiries[$key])) {
CacheItem::validateKey($key);
}
unset($this->values[$key], $this->expiries[$key]);

return true;
}

/**
* {@inheritdoc}
*/
Expand Down Expand Up @@ -156,8 +193,110 @@ public function commit()
/**
* {@inheritdoc}
*/
public function delete(string $key): bool
public function clear()
{
return $this->deleteItem($key);
$this->values = $this->expiries = [];

return true;
}

/**
* Returns all cached values, with cache miss as null.
*
* @return array
*/
public function getValues()
{
if (!$this->storeSerialized) {
return $this->values;
}

$values = $this->values;
foreach ($values as $k => $v) {
if (null === $v || 'N;' === $v) {
continue;
}
if (!\is_string($v) || !isset($v[2]) || ':' !== $v[1]) {
$values[$k] = serialize($v);
}
}

return $values;
}

/**
* {@inheritdoc}
*/
public function reset()
{
$this->clear();
}

private function generateItems(array $keys, $now, $f)
{
foreach ($keys as $i => $key) {
if (!$isHit = isset($this->expiries[$key]) && ($this->expiries[$key] > $now || !$this->deleteItem($key))) {
$this->values[$key] = $value = null;
} else {
$value = $this->storeSerialized ? $this->unfreeze($key, $isHit) : $this->values[$key];
}
unset($keys[$i]);

yield $key => $f($key, $value, $isHit);
}

foreach ($keys as $key) {
yield $key => $f($key, null, false);
}
}

private function freeze($value, $key)
{
if (null === $value) {
return 'N;';
}
if (\is_string($value)) {
// Serialize strings if they could be confused with serialized objects or arrays
if ('N;' === $value || (isset($value[2]) && ':' === $value[1])) {
return serialize($value);
}
} elseif (!\is_scalar($value)) {
try {
$serialized = serialize($value);
} catch (\Exception $e) {
$type = \is_object($value) ? \get_class($value) : \gettype($value);
$message = sprintf('Failed to save key "{key}" of type %s: %s', $type, $e->getMessage());
CacheItem::log($this->logger, $message, ['key' => substr($id, \strlen($this->namespace)), 'exception' => $e]);

return;
}
// Keep value serialized if it contains any objects or any internal references
if ('C' === $serialized[0] || 'O' === $serialized[0] || preg_match('/;[OCRr]:[1-9]/', $serialized)) {
return $serialized;
}
}

return $value;
}

private function unfreeze(string $key, bool &$isHit)
{
if ('N;' === $value = $this->values[$key]) {
return null;
}
if (\is_string($value) && isset($value[2]) && ':' === $value[1]) {
try {
$value = unserialize($value);
} catch (\Exception $e) {
CacheItem::log($this->logger, 'Failed to unserialize key "{key}": '.$e->getMessage(), ['key' => $key, 'exception' => $e]);
$value = false;
}
if (false === $value) {
$this->values[$key] = $value = null;
$isHit = false;
}
}

return $value;
}
}
82 changes: 80 additions & 2 deletions src/Symfony/Component/Cache/Adapter/DoctrineAdapter.php
Expand Up @@ -12,16 +12,94 @@
namespace Symfony\Component\Cache\Adapter;

use Doctrine\Common\Cache\CacheProvider;
use Symfony\Component\Cache\Traits\DoctrineTrait;

/**
* @author Nicolas Grekas <p@tchwork.com>
*/
class DoctrineAdapter extends AbstractAdapter
{
use DoctrineTrait;
private $provider;

public function __construct(CacheProvider $provider, string $namespace = '', int $defaultLifetime = 0)
{
parent::__construct('', $defaultLifetime);
$this->provider = $provider;
$provider->setNamespace($namespace);
}

/**
* {@inheritdoc}
*/
public function reset()
{
parent::reset();
$this->provider->setNamespace($this->provider->getNamespace());
}

/**
* {@inheritdoc}
*/
protected function doFetch(array $ids)
{
$unserializeCallbackHandler = ini_set('unserialize_callback_func', parent::class.'::handleUnserializeCallback');
try {
return $this->provider->fetchMultiple($ids);
} catch (\Error $e) {
$trace = $e->getTrace();

if (isset($trace[0]['function']) && !isset($trace[0]['class'])) {
switch ($trace[0]['function']) {
case 'unserialize':
case 'apcu_fetch':
case 'apc_fetch':
throw new \ErrorException($e->getMessage(), $e->getCode(), E_ERROR, $e->getFile(), $e->getLine());
}
}

throw $e;
} finally {
ini_set('unserialize_callback_func', $unserializeCallbackHandler);
}
}

/**
* {@inheritdoc}
*/
protected function doHave($id)
{
return $this->provider->contains($id);
}

/**
* {@inheritdoc}
*/
protected function doClear($namespace)
{
$namespace = $this->provider->getNamespace();

return isset($namespace[0])
? $this->provider->deleteAll()
: $this->provider->flushAll();
}

/**
* {@inheritdoc}
*/
protected function doDelete(array $ids)
{
$ok = true;
foreach ($ids as $id) {
$ok = $this->provider->delete($id) && $ok;
}

return $ok;
}

/**
* {@inheritdoc}
*/
protected function doSave(array $values, $lifetime)
{
return $this->provider->saveMultiple($values, $lifetime);
}
}

0 comments on commit 4a437ab

Please sign in to comment.