[Cache] Move adapter implementations to traits

This commit is contained in:
Nicolas Grekas 2017-01-03 19:50:14 +01:00
parent 848a33ed3e
commit 99ae9d6a35
14 changed files with 481 additions and 392 deletions

View File

@ -13,31 +13,24 @@ namespace Symfony\Component\Cache\Adapter;
use Psr\Cache\CacheItemInterface;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerAwareTrait;
use Psr\Log\LoggerInterface;
use Symfony\Component\Cache\CacheItem;
use Symfony\Component\Cache\Exception\InvalidArgumentException;
use Symfony\Component\Cache\Traits\AbstractTrait;
/**
* @author Nicolas Grekas <p@tchwork.com>
*/
abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface
{
use LoggerAwareTrait;
use AbstractTrait;
private static $apcuSupported;
private static $phpFilesSupported;
private $namespace;
private $deferred = array();
private $createCacheItem;
private $mergeByLifetime;
/**
* @var int|null The maximum length to enforce for identifiers or null when no limit applies
*/
protected $maxIdLength;
protected function __construct($namespace = '', $defaultLifetime = 0)
{
$this->namespace = '' === $namespace ? '' : $this->getId($namespace).':';
@ -130,52 +123,6 @@ abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface
throw new InvalidArgumentException(sprintf('Unsupported DSN: %s.', $dsn));
}
/**
* Fetches several cache items.
*
* @param array $ids The cache identifiers to fetch
*
* @return array|\Traversable The corresponding values found in the cache
*/
abstract protected function doFetch(array $ids);
/**
* Confirms if the cache contains specified cache item.
*
* @param string $id The identifier for which to check existence
*
* @return bool True if item exists in the cache, false otherwise
*/
abstract protected function doHave($id);
/**
* Deletes all items in the pool.
*
* @param string The prefix used for all identifiers managed by this pool
*
* @return bool True if the pool was successfully cleared, false otherwise
*/
abstract protected function doClear($namespace);
/**
* Removes multiple items from the pool.
*
* @param array $ids An array of identifiers that should be removed from the pool
*
* @return bool True if the items were successfully removed, false otherwise
*/
abstract protected function doDelete(array $ids);
/**
* Persists several cache items immediately.
*
* @param array $values The values to cache, indexed by their cache identifier
* @param int $lifetime The lifetime of the cached values, 0 for persisting until manual cleaning
*
* @return array|bool The identifiers that failed to be cached or a boolean stating if caching succeeded or not
*/
abstract protected function doSave(array $values, $lifetime);
/**
* {@inheritdoc}
*/
@ -225,87 +172,6 @@ abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface
return $this->generateItems($items, $ids);
}
/**
* {@inheritdoc}
*/
public function hasItem($key)
{
$id = $this->getId($key);
if (isset($this->deferred[$key])) {
$this->commit();
}
try {
return $this->doHave($id);
} catch (\Exception $e) {
CacheItem::log($this->logger, 'Failed to check if key "{key}" is cached', array('key' => $key, 'exception' => $e));
return false;
}
}
/**
* {@inheritdoc}
*/
public function clear()
{
$this->deferred = array();
try {
return $this->doClear($this->namespace);
} catch (\Exception $e) {
CacheItem::log($this->logger, 'Failed to clear the cache', array('exception' => $e));
return false;
}
}
/**
* {@inheritdoc}
*/
public function deleteItem($key)
{
return $this->deleteItems(array($key));
}
/**
* {@inheritdoc}
*/
public function deleteItems(array $keys)
{
$ids = array();
foreach ($keys as $key) {
$ids[$key] = $this->getId($key);
unset($this->deferred[$key]);
}
try {
if ($this->doDelete($ids)) {
return true;
}
} catch (\Exception $e) {
}
$ok = true;
// When bulk-delete failed, retry each item individually
foreach ($ids as $key => $id) {
try {
$e = null;
if ($this->doDelete(array($id))) {
continue;
}
} catch (\Exception $e) {
}
CacheItem::log($this->logger, 'Failed to delete key "{key}"', array('key' => $key, 'exception' => $e));
$ok = false;
}
return $ok;
}
/**
* {@inheritdoc}
*/
@ -394,47 +260,6 @@ abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface
}
}
/**
* Like the native unserialize() function but throws an exception if anything goes wrong.
*
* @param string $value
*
* @return mixed
*
* @throws \Exception
*/
protected static function unserialize($value)
{
if ('b:0;' === $value) {
return false;
}
$unserializeCallbackHandler = ini_set('unserialize_callback_func', __CLASS__.'::handleUnserializeCallback');
try {
if (false !== $value = unserialize($value)) {
return $value;
}
throw new \DomainException('Failed to unserialize cached value');
} catch (\Error $e) {
throw new \ErrorException($e->getMessage(), $e->getCode(), E_ERROR, $e->getFile(), $e->getLine());
} finally {
ini_set('unserialize_callback_func', $unserializeCallbackHandler);
}
}
private function getId($key)
{
CacheItem::validateKey($key);
if (null === $this->maxIdLength) {
return $this->namespace.$key;
}
if (strlen($id = $this->namespace.$key) > $this->maxIdLength) {
$id = $this->namespace.substr_replace(base64_encode(hash('sha256', $key, true)), ':', -22);
}
return $id;
}
private function generateItems($items, &$keys)
{
$f = $this->createCacheItem;
@ -453,12 +278,4 @@ abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface
yield $key => $f($key, null, false);
}
}
/**
* @internal
*/
public static function handleUnserializeCallback($class)
{
throw new \DomainException('Class not found: '.$class);
}
}

View File

@ -13,19 +13,16 @@ namespace Symfony\Component\Cache\Adapter;
use Psr\Cache\CacheItemInterface;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerAwareTrait;
use Symfony\Component\Cache\CacheItem;
use Symfony\Component\Cache\Traits\ArrayTrait;
/**
* @author Nicolas Grekas <p@tchwork.com>
*/
class ArrayAdapter implements AdapterInterface, LoggerAwareInterface
{
use LoggerAwareTrait;
use ArrayTrait;
private $storeSerialized;
private $values = array();
private $expiries = array();
private $createCacheItem;
/**
@ -86,49 +83,7 @@ class ArrayAdapter implements AdapterInterface, LoggerAwareInterface
CacheItem::validateKey($key);
}
return $this->generateItems($keys, time());
}
/**
* Returns all cached values, with cache miss as null.
*
* @return array
*/
public function getValues()
{
return $this->values;
}
/**
* {@inheritdoc}
*/
public function hasItem($key)
{
CacheItem::validateKey($key);
return isset($this->expiries[$key]) && ($this->expiries[$key] >= time() || !$this->deleteItem($key));
}
/**
* {@inheritdoc}
*/
public function clear()
{
$this->values = $this->expiries = array();
return true;
}
/**
* {@inheritdoc}
*/
public function deleteItem($key)
{
CacheItem::validateKey($key);
unset($this->values[$key], $this->expiries[$key]);
return true;
return $this->generateItems($keys, time(), $this->createCacheItem);
}
/**
@ -196,35 +151,4 @@ class ArrayAdapter implements AdapterInterface, LoggerAwareInterface
{
return true;
}
private function generateItems(array $keys, $now)
{
$f = $this->createCacheItem;
foreach ($keys as $i => $key) {
try {
if (!$isHit = isset($this->expiries[$key]) && ($this->expiries[$key] >= $now || !$this->deleteItem($key))) {
$this->values[$key] = $value = null;
} elseif (!$this->storeSerialized) {
$value = $this->values[$key];
} elseif ('b:0;' === $value = $this->values[$key]) {
$value = false;
} elseif (false === $value = unserialize($value)) {
$this->values[$key] = $value = null;
$isHit = false;
}
} catch (\Exception $e) {
CacheItem::log($this->logger, 'Failed to unserialize key "{key}"', array('key' => $key, 'exception' => $e));
$this->values[$key] = $value = null;
$isHit = false;
}
unset($keys[$i]);
yield $key => $f($key, $value, $isHit);
}
foreach ($keys as $key) {
yield $key => $f($key, null, false);
}
}
}

View File

@ -15,6 +15,7 @@ use Psr\Cache\CacheItemInterface;
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\Cache\CacheItem;
use Symfony\Component\Cache\Exception\InvalidArgumentException;
use Symfony\Component\Cache\Traits\PhpArrayTrait;
/**
* Caches items at warm up time using a PHP array that is stored in shared memory by OPCache since PHP 7.0.
@ -25,10 +26,9 @@ use Symfony\Component\Cache\Exception\InvalidArgumentException;
*/
class PhpArrayAdapter implements AdapterInterface
{
private $file;
private $values;
use PhpArrayTrait;
private $createCacheItem;
private $fallbackPool;
/**
* @param string $file The PHP file were values are cached
@ -75,89 +75,6 @@ class PhpArrayAdapter implements AdapterInterface
return $fallbackPool;
}
/**
* Store an array of cached values.
*
* @param array $values The cached values
*/
public function warmUp(array $values)
{
if (file_exists($this->file)) {
if (!is_file($this->file)) {
throw new InvalidArgumentException(sprintf('Cache path exists and is not a file: %s.', $this->file));
}
if (!is_writable($this->file)) {
throw new InvalidArgumentException(sprintf('Cache file is not writable: %s.', $this->file));
}
} else {
$directory = dirname($this->file);
if (!is_dir($directory) && !@mkdir($directory, 0777, true)) {
throw new InvalidArgumentException(sprintf('Cache directory does not exist and cannot be created: %s.', $directory));
}
if (!is_writable($directory)) {
throw new InvalidArgumentException(sprintf('Cache directory is not writable: %s.', $directory));
}
}
$dump = <<<'EOF'
<?php
// This file has been auto-generated by the Symfony Cache Component.
return array(
EOF;
foreach ($values as $key => $value) {
CacheItem::validateKey(is_int($key) ? (string) $key : $key);
if (null === $value || is_object($value)) {
try {
$value = serialize($value);
} catch (\Exception $e) {
throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable %s value.', $key, get_class($value)), 0, $e);
}
} elseif (is_array($value)) {
try {
$serialized = serialize($value);
$unserialized = unserialize($serialized);
} catch (\Exception $e) {
throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable array value.', $key), 0, $e);
}
// Store arrays serialized if they contain any objects or references
if ($unserialized !== $value || (false !== strpos($serialized, ';R:') && preg_match('/;R:[1-9]/', $serialized))) {
$value = $serialized;
}
} elseif (is_string($value)) {
// Serialize strings if they could be confused with serialized objects or arrays
if ('N;' === $value || (isset($value[2]) && ':' === $value[1])) {
$value = serialize($value);
}
} elseif (!is_scalar($value)) {
throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable %s value.', $key, gettype($value)));
}
$dump .= var_export($key, true).' => '.var_export($value, true).",\n";
}
$dump .= "\n);\n";
$dump = str_replace("' . \"\\0\" . '", "\0", $dump);
$tmpFile = uniqid($this->file, true);
file_put_contents($tmpFile, $dump);
@chmod($tmpFile, 0666);
unset($serialized, $unserialized, $value, $dump);
@rename($tmpFile, $this->file);
$this->values = (include $this->file) ?: array();
}
/**
* {@inheritdoc}
*/
@ -228,18 +145,6 @@ EOF;
return isset($this->values[$key]) || $this->fallbackPool->hasItem($key);
}
/**
* {@inheritdoc}
*/
public function clear()
{
$this->values = array();
$cleared = @unlink($this->file) || !file_exists($this->file);
return $this->fallbackPool->clear() && $cleared;
}
/**
* {@inheritdoc}
*/
@ -317,14 +222,6 @@ EOF;
return $this->fallbackPool->commit();
}
/**
* Load the cache file.
*/
private function initialize()
{
$this->values = file_exists($this->file) ? (include $this->file ?: array()) : array();
}
/**
* Generator for items.
*

View File

@ -0,0 +1,209 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Traits;
use Psr\Log\LoggerAwareTrait;
use Symfony\Component\Cache\CacheItem;
/**
* @author Nicolas Grekas <p@tchwork.com>
*
* @internal
*/
trait AbstractTrait
{
use LoggerAwareTrait;
private $namespace;
private $deferred = array();
/**
* @var int|null The maximum length to enforce for identifiers or null when no limit applies
*/
protected $maxIdLength;
/**
* Fetches several cache items.
*
* @param array $ids The cache identifiers to fetch
*
* @return array|\Traversable The corresponding values found in the cache
*/
abstract protected function doFetch(array $ids);
/**
* Confirms if the cache contains specified cache item.
*
* @param string $id The identifier for which to check existence
*
* @return bool True if item exists in the cache, false otherwise
*/
abstract protected function doHave($id);
/**
* Deletes all items in the pool.
*
* @param string The prefix used for all identifiers managed by this pool
*
* @return bool True if the pool was successfully cleared, false otherwise
*/
abstract protected function doClear($namespace);
/**
* Removes multiple items from the pool.
*
* @param array $ids An array of identifiers that should be removed from the pool
*
* @return bool True if the items were successfully removed, false otherwise
*/
abstract protected function doDelete(array $ids);
/**
* Persists several cache items immediately.
*
* @param array $values The values to cache, indexed by their cache identifier
* @param int $lifetime The lifetime of the cached values, 0 for persisting until manual cleaning
*
* @return array|bool The identifiers that failed to be cached or a boolean stating if caching succeeded or not
*/
abstract protected function doSave(array $values, $lifetime);
/**
* {@inheritdoc}
*/
public function hasItem($key)
{
$id = $this->getId($key);
if (isset($this->deferred[$key])) {
$this->commit();
}
try {
return $this->doHave($id);
} catch (\Exception $e) {
CacheItem::log($this->logger, 'Failed to check if key "{key}" is cached', array('key' => $key, 'exception' => $e));
return false;
}
}
/**
* {@inheritdoc}
*/
public function clear()
{
$this->deferred = array();
try {
return $this->doClear($this->namespace);
} catch (\Exception $e) {
CacheItem::log($this->logger, 'Failed to clear the cache', array('exception' => $e));
return false;
}
}
/**
* {@inheritdoc}
*/
public function deleteItem($key)
{
return $this->deleteItems(array($key));
}
/**
* {@inheritdoc}
*/
public function deleteItems(array $keys)
{
$ids = array();
foreach ($keys as $key) {
$ids[$key] = $this->getId($key);
unset($this->deferred[$key]);
}
try {
if ($this->doDelete($ids)) {
return true;
}
} catch (\Exception $e) {
}
$ok = true;
// When bulk-delete failed, retry each item individually
foreach ($ids as $key => $id) {
try {
$e = null;
if ($this->doDelete(array($id))) {
continue;
}
} catch (\Exception $e) {
}
CacheItem::log($this->logger, 'Failed to delete key "{key}"', array('key' => $key, 'exception' => $e));
$ok = false;
}
return $ok;
}
/**
* Like the native unserialize() function but throws an exception if anything goes wrong.
*
* @param string $value
*
* @return mixed
*
* @throws \Exception
*/
protected static function unserialize($value)
{
if ('b:0;' === $value) {
return false;
}
$unserializeCallbackHandler = ini_set('unserialize_callback_func', __CLASS__.'::handleUnserializeCallback');
try {
if (false !== $value = unserialize($value)) {
return $value;
}
throw new \DomainException('Failed to unserialize cached value');
} catch (\Error $e) {
throw new \ErrorException($e->getMessage(), $e->getCode(), E_ERROR, $e->getFile(), $e->getLine());
} finally {
ini_set('unserialize_callback_func', $unserializeCallbackHandler);
}
}
private function getId($key)
{
CacheItem::validateKey($key);
if (null === $this->maxIdLength) {
return $this->namespace.$key;
}
if (strlen($id = $this->namespace.$key) > $this->maxIdLength) {
$id = $this->namespace.substr_replace(base64_encode(hash('sha256', $key, true)), ':', -22);
}
return $id;
}
/**
* @internal
*/
public static function handleUnserializeCallback($class)
{
throw new \DomainException('Class not found: '.$class);
}
}

View File

@ -9,15 +9,17 @@
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Adapter;
namespace Symfony\Component\Cache\Traits;
use Symfony\Component\Cache\CacheItem;
use Symfony\Component\Cache\Exception\CacheException;
/**
* @author Nicolas Grekas <p@tchwork.com>
*
* @internal
*/
class ApcuAdapter extends AbstractAdapter
trait ApcuTrait
{
public static function isSupported()
{

View File

@ -0,0 +1,100 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Traits;
use Psr\Log\LoggerAwareTrait;
use Symfony\Component\Cache\CacheItem;
/**
* @author Nicolas Grekas <p@tchwork.com>
*
* @internal
*/
trait ArrayTrait
{
use LoggerAwareTrait;
private $storeSerialized;
private $values = array();
private $expiries = array();
/**
* Returns all cached values, with cache miss as null.
*
* @return array
*/
public function getValues()
{
return $this->values;
}
/**
* {@inheritdoc}
*/
public function hasItem($key)
{
CacheItem::validateKey($key);
return isset($this->expiries[$key]) && ($this->expiries[$key] >= time() || !$this->deleteItem($key));
}
/**
* {@inheritdoc}
*/
public function clear()
{
$this->values = $this->expiries = array();
return true;
}
/**
* {@inheritdoc}
*/
public function deleteItem($key)
{
CacheItem::validateKey($key);
unset($this->values[$key], $this->expiries[$key]);
return true;
}
private function generateItems(array $keys, $now, $f)
{
foreach ($keys as $i => $key) {
try {
if (!$isHit = isset($this->expiries[$key]) && ($this->expiries[$key] >= $now || !$this->deleteItem($key))) {
$this->values[$key] = $value = null;
} elseif (!$this->storeSerialized) {
$value = $this->values[$key];
} elseif ('b:0;' === $value = $this->values[$key]) {
$value = false;
} elseif (false === $value = unserialize($value)) {
$this->values[$key] = $value = null;
$isHit = false;
}
} catch (\Exception $e) {
CacheItem::log($this->logger, 'Failed to unserialize key "{key}"', array('key' => $key, 'exception' => $e));
$this->values[$key] = $value = null;
$isHit = false;
}
unset($keys[$i]);
yield $key => $f($key, $value, $isHit);
}
foreach ($keys as $key) {
yield $key => $f($key, null, false);
}
}
}

View File

@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Adapter;
namespace Symfony\Component\Cache\Traits;
use Doctrine\Common\Cache\CacheProvider;
/**
* @author Nicolas Grekas <p@tchwork.com>
*
* @internal
*/
class DoctrineAdapter extends AbstractAdapter
trait DoctrineTrait
{
private $provider;

View File

@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Adapter;
namespace Symfony\Component\Cache\Traits;
use Symfony\Component\Cache\Exception\InvalidArgumentException;
@ -18,7 +18,7 @@ use Symfony\Component\Cache\Exception\InvalidArgumentException;
*
* @internal
*/
trait FilesystemAdapterTrait
trait FilesystemCommonTrait
{
private $directory;
private $tmp;

View File

@ -9,16 +9,18 @@
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Adapter;
namespace Symfony\Component\Cache\Traits;
use Symfony\Component\Cache\Exception\CacheException;
/**
* @author Nicolas Grekas <p@tchwork.com>
*
* @internal
*/
class FilesystemAdapter extends AbstractAdapter
trait FilesystemTrait
{
use FilesystemAdapterTrait;
use FilesystemCommonTrait;
public function __construct($namespace = '', $defaultLifetime = 0, $directory = null)
{

View File

@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Adapter;
namespace Symfony\Component\Cache\Traits;
use Symfony\Component\Cache\Exception\CacheException;
use Symfony\Component\Cache\Exception\InvalidArgumentException;
@ -17,8 +17,10 @@ use Symfony\Component\Cache\Exception\InvalidArgumentException;
/**
* @author Rob Frawley 2nd <rmf@src.run>
* @author Nicolas Grekas <p@tchwork.com>
*
* @internal
*/
class MemcachedAdapter extends AbstractAdapter
trait MemcachedTrait
{
private static $defaultClientOptions = array(
'persistent_id' => null,
@ -26,8 +28,6 @@ class MemcachedAdapter extends AbstractAdapter
'password' => null,
);
protected $maxIdLength = 250;
private $client;
public static function isSupported()

View File

@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Adapter;
namespace Symfony\Component\Cache\Traits;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Driver\ServerInfoAwareConnection;
@ -17,10 +17,11 @@ use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Schema\Schema;
use Symfony\Component\Cache\Exception\InvalidArgumentException;
class PdoAdapter extends AbstractAdapter
/**
* @internal
*/
trait PdoTrait
{
protected $maxIdLength = 255;
private $conn;
private $dsn;
private $driver;

View File

@ -0,0 +1,131 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Traits;
use Symfony\Component\Cache\CacheItem;
use Symfony\Component\Cache\Exception\InvalidArgumentException;
/**
* @author Titouan Galopin <galopintitouan@gmail.com>
* @author Nicolas Grekas <p@tchwork.com>
*
* @internal
*/
trait PhpArrayTrait
{
private $file;
private $values;
private $fallbackPool;
/**
* Store an array of cached values.
*
* @param array $values The cached values
*/
public function warmUp(array $values)
{
if (file_exists($this->file)) {
if (!is_file($this->file)) {
throw new InvalidArgumentException(sprintf('Cache path exists and is not a file: %s.', $this->file));
}
if (!is_writable($this->file)) {
throw new InvalidArgumentException(sprintf('Cache file is not writable: %s.', $this->file));
}
} else {
$directory = dirname($this->file);
if (!is_dir($directory) && !@mkdir($directory, 0777, true)) {
throw new InvalidArgumentException(sprintf('Cache directory does not exist and cannot be created: %s.', $directory));
}
if (!is_writable($directory)) {
throw new InvalidArgumentException(sprintf('Cache directory is not writable: %s.', $directory));
}
}
$dump = <<<'EOF'
<?php
// This file has been auto-generated by the Symfony Cache Component.
return array(
EOF;
foreach ($values as $key => $value) {
CacheItem::validateKey(is_int($key) ? (string) $key : $key);
if (null === $value || is_object($value)) {
try {
$value = serialize($value);
} catch (\Exception $e) {
throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable %s value.', $key, get_class($value)), 0, $e);
}
} elseif (is_array($value)) {
try {
$serialized = serialize($value);
$unserialized = unserialize($serialized);
} catch (\Exception $e) {
throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable array value.', $key), 0, $e);
}
// Store arrays serialized if they contain any objects or references
if ($unserialized !== $value || (false !== strpos($serialized, ';R:') && preg_match('/;R:[1-9]/', $serialized))) {
$value = $serialized;
}
} elseif (is_string($value)) {
// Serialize strings if they could be confused with serialized objects or arrays
if ('N;' === $value || (isset($value[2]) && ':' === $value[1])) {
$value = serialize($value);
}
} elseif (!is_scalar($value)) {
throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable %s value.', $key, gettype($value)));
}
$dump .= var_export($key, true).' => '.var_export($value, true).",\n";
}
$dump .= "\n);\n";
$dump = str_replace("' . \"\\0\" . '", "\0", $dump);
$tmpFile = uniqid($this->file, true);
file_put_contents($tmpFile, $dump);
@chmod($tmpFile, 0666);
unset($serialized, $unserialized, $value, $dump);
@rename($tmpFile, $this->file);
$this->values = (include $this->file) ?: array();
}
/**
* {@inheritdoc}
*/
public function clear()
{
$this->values = array();
$cleared = @unlink($this->file) || !file_exists($this->file);
return $this->fallbackPool->clear() && $cleared;
}
/**
* Load the cache file.
*/
private function initialize()
{
$this->values = @(include $this->file) ?: array();
}
}

View File

@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Adapter;
namespace Symfony\Component\Cache\Traits;
use Symfony\Component\Cache\Exception\CacheException;
use Symfony\Component\Cache\Exception\InvalidArgumentException;
@ -17,10 +17,12 @@ use Symfony\Component\Cache\Exception\InvalidArgumentException;
/**
* @author Piotr Stankowski <git@trakos.pl>
* @author Nicolas Grekas <p@tchwork.com>
*
* @internal
*/
class PhpFilesAdapter extends AbstractAdapter
trait PhpFilesTrait
{
use FilesystemAdapterTrait;
use FilesystemCommonTrait;
private $includeHandler;

View File

@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Adapter;
namespace Symfony\Component\Cache\Traits;
use Predis\Connection\Factory;
use Predis\Connection\Aggregate\PredisCluster;
@ -19,8 +19,10 @@ use Symfony\Component\Cache\Exception\InvalidArgumentException;
/**
* @author Aurimas Niekis <aurimas@niekis.lt>
* @author Nicolas Grekas <p@tchwork.com>
*
* @internal
*/
class RedisAdapter extends AbstractAdapter
trait RedisTrait
{
private static $defaultConnectionOptions = array(
'class' => null,