From 8605417b5557355fd4049a5a2f4bebba641b947f Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 2 Feb 2016 16:39:10 +0100 Subject: [PATCH] [Cache] Don't clone, serialize --- .../Cache/Adapter/AbstractAdapter.php | 7 ---- .../Component/Cache/Adapter/ArrayAdapter.php | 35 ++++++++++++++----- src/Symfony/Component/Cache/CacheItem.php | 9 +---- 3 files changed, 27 insertions(+), 24 deletions(-) diff --git a/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php b/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php index 0cf42f7addb7..1d6e843e37a0 100644 --- a/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php @@ -276,13 +276,6 @@ public function saveDeferred(CacheItemInterface $item) if (!$item instanceof CacheItem) { return false; } - try { - $item = clone $item; - } catch (\Exception $e) { - $value = $item->get(); - $type = is_object($value) ? get_class($value) : gettype($value); - CacheItem::log($this->logger, 'Failed to clone key "{key}" ({type})', array('key' => $key, 'type' => $type, 'exception' => $e)); - } $this->deferred[$item->getKey()] = $item; return true; diff --git a/src/Symfony/Component/Cache/Adapter/ArrayAdapter.php b/src/Symfony/Component/Cache/Adapter/ArrayAdapter.php index 64d0a4696d52..7e7e6a6f8f29 100644 --- a/src/Symfony/Component/Cache/Adapter/ArrayAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/ArrayAdapter.php @@ -25,12 +25,18 @@ class ArrayAdapter implements CacheItemPoolInterface, LoggerAwareInterface { use LoggerAwareTrait; + private $storeSerialized; private $values = array(); private $expiries = array(); private $createCacheItem; - public function __construct($defaultLifetime = 0) + /** + * @param int $defaultLifetime + * @param bool $storeSerialized Disabling serialization can lead to cache corruptions when storing mutable values but increases performance otherwise. + */ + public function __construct($defaultLifetime = 0, $storeSerialized = true) { + $this->storeSerialized = $storeSerialized; $this->createCacheItem = \Closure::bind( function ($key, $value, $isHit) use ($defaultLifetime) { $item = new CacheItem(); @@ -51,10 +57,16 @@ function ($key, $value, $isHit) use ($defaultLifetime) { */ public function getItem($key) { + if (!$isHit = $this->hasItem($key)) { + $value = null; + } elseif ($this->storeSerialized) { + $value = unserialize($this->values[$key]); + } else { + $value = $this->values[$key]; + } $f = $this->createCacheItem; - $isHit = $this->hasItem($key); - return $f($key, $isHit ? $this->values[$key] : null, $isHit); + return $f($key, $value, $isHit); } /** @@ -125,13 +137,12 @@ public function save(CacheItemInterface $item) if (0 > $lifetime) { return true; } - - if (is_object($value)) { + if ($this->storeSerialized) { try { - $value = clone $value; + $value = serialize($value); } catch (\Exception $e) { $type = is_object($value) ? get_class($value) : gettype($value); - CacheItem::log($this->logger, 'Failed to clone key "{key}" ({type})', array('key' => $key, 'type' => $type, 'exception' => $e)); + CacheItem::log($this->logger, 'Failed to save key "{key}" ({type})', array('key' => $key, 'type' => $type, 'exception' => $e)); return false; } @@ -179,9 +190,15 @@ private function generateItems(array $keys) $f = $this->createCacheItem; foreach ($keys as $key) { - $isHit = isset($this->expiries[$key]) && ($this->expiries[$key] >= time() || !$this->deleteItem($key)); + if (!$isHit = isset($this->expiries[$key]) && ($this->expiries[$key] >= time() || !$this->deleteItem($key))) { + $value = null; + } elseif ($this->storeSerialized) { + $value = unserialize($this->values[$key]); + } else { + $value = $this->values[$key]; + } - yield $key => $f($key, $isHit ? $this->values[$key] : null, $isHit); + yield $key => $f($key, $value, $isHit); } } } diff --git a/src/Symfony/Component/Cache/CacheItem.php b/src/Symfony/Component/Cache/CacheItem.php index e46cdef33cf3..8b0ac2c33df3 100644 --- a/src/Symfony/Component/Cache/CacheItem.php +++ b/src/Symfony/Component/Cache/CacheItem.php @@ -31,13 +31,6 @@ final class CacheItem implements CacheItemInterface private $lifetime; private $defaultLifetime; - public function __clone() - { - if (is_object($this->value)) { - $this->value = clone $this->value; - } - } - /** * {@inheritdoc} */ @@ -112,7 +105,7 @@ public function expiresAfter($time) * * @internal */ - public function log(LoggerInterface $logger = null, $message, $context = array()) + public static function log(LoggerInterface $logger = null, $message, $context = array()) { if ($logger) { $logger->warning($message, $context);