[Cache] make PhpMarshaller handle hard references
This commit is contained in:
parent
f96753b9ab
commit
bc5d208584
|
@ -16,7 +16,6 @@ use Psr\Cache\CacheItemPoolInterface;
|
||||||
use Symfony\Component\Cache\CacheInterface;
|
use Symfony\Component\Cache\CacheInterface;
|
||||||
use Symfony\Component\Cache\CacheItem;
|
use Symfony\Component\Cache\CacheItem;
|
||||||
use Symfony\Component\Cache\Exception\InvalidArgumentException;
|
use Symfony\Component\Cache\Exception\InvalidArgumentException;
|
||||||
use Symfony\Component\Cache\Marshaller\DefaultMarshaller;
|
|
||||||
use Symfony\Component\Cache\PruneableInterface;
|
use Symfony\Component\Cache\PruneableInterface;
|
||||||
use Symfony\Component\Cache\ResettableInterface;
|
use Symfony\Component\Cache\ResettableInterface;
|
||||||
use Symfony\Component\Cache\Traits\GetTrait;
|
use Symfony\Component\Cache\Traits\GetTrait;
|
||||||
|
@ -35,7 +34,6 @@ class PhpArrayAdapter implements AdapterInterface, CacheInterface, PruneableInte
|
||||||
use GetTrait;
|
use GetTrait;
|
||||||
|
|
||||||
private $createCacheItem;
|
private $createCacheItem;
|
||||||
private $marshaller;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $file The PHP file were values are cached
|
* @param string $file The PHP file were values are cached
|
||||||
|
@ -106,9 +104,6 @@ class PhpArrayAdapter implements AdapterInterface, CacheInterface, PruneableInte
|
||||||
if ($value instanceof \Closure) {
|
if ($value instanceof \Closure) {
|
||||||
return $value();
|
return $value();
|
||||||
}
|
}
|
||||||
if (\is_string($value) && isset($value[2]) && ':' === $value[1]) {
|
|
||||||
return ($this->marshaller ?? $this->marshaller = new DefaultMarshaller())->unmarshall($value);
|
|
||||||
}
|
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
unset($this->keys[$key]);
|
unset($this->keys[$key]);
|
||||||
goto get_from_pool;
|
goto get_from_pool;
|
||||||
|
@ -144,13 +139,6 @@ class PhpArrayAdapter implements AdapterInterface, CacheInterface, PruneableInte
|
||||||
$value = null;
|
$value = null;
|
||||||
$isHit = false;
|
$isHit = false;
|
||||||
}
|
}
|
||||||
} elseif (\is_string($value) && isset($value[2]) && ':' === $value[1]) {
|
|
||||||
try {
|
|
||||||
$value = unserialize($value);
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
$value = null;
|
|
||||||
$isHit = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$f = $this->createCacheItem;
|
$f = $this->createCacheItem;
|
||||||
|
@ -284,12 +272,6 @@ class PhpArrayAdapter implements AdapterInterface, CacheInterface, PruneableInte
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
yield $key => $f($key, null, false);
|
yield $key => $f($key, null, false);
|
||||||
}
|
}
|
||||||
} elseif (\is_string($value) && isset($value[2]) && ':' === $value[1]) {
|
|
||||||
try {
|
|
||||||
yield $key => $f($key, $this->unserializeValue($value), true);
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
yield $key => $f($key, null, false);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
yield $key => $f($key, $value, true);
|
yield $key => $f($key, $value, true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,8 +12,10 @@
|
||||||
namespace Symfony\Component\Cache\Marshaller;
|
namespace Symfony\Component\Cache\Marshaller;
|
||||||
|
|
||||||
use Symfony\Component\Cache\Marshaller\PhpMarshaller\Configurator;
|
use Symfony\Component\Cache\Marshaller\PhpMarshaller\Configurator;
|
||||||
|
use Symfony\Component\Cache\Marshaller\PhpMarshaller\Marshaller;
|
||||||
use Symfony\Component\Cache\Marshaller\PhpMarshaller\Reference;
|
use Symfony\Component\Cache\Marshaller\PhpMarshaller\Reference;
|
||||||
use Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry;
|
use Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry;
|
||||||
|
use Symfony\Component\Cache\Marshaller\PhpMarshaller\Values;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Nicolas Grekas <p@tchwork.com>
|
* @author Nicolas Grekas <p@tchwork.com>
|
||||||
|
@ -27,14 +29,31 @@ use Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry;
|
||||||
*/
|
*/
|
||||||
class PhpMarshaller
|
class PhpMarshaller
|
||||||
{
|
{
|
||||||
public static function marshall($value, int &$objectsCount)
|
public static function marshall($value, bool &$isStaticValue = null): string
|
||||||
{
|
{
|
||||||
if (!\is_object($value) && !\is_array($value)) {
|
$isStaticValue = true;
|
||||||
return $value;
|
|
||||||
|
if (!\is_object($value) && !(\is_array($value) && $value) && !$value instanceof \__PHP_Incomplete_Class && !\is_resource($value)) {
|
||||||
|
return var_export($value, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
$objectsPool = new \SplObjectStorage();
|
$objectsPool = new \SplObjectStorage();
|
||||||
$value = array($value);
|
$refsPool = array();
|
||||||
$objectsCount = self::doMarshall($value, $objectsPool);
|
$objectsCount = 0;
|
||||||
|
|
||||||
|
try {
|
||||||
|
$value = Marshaller::marshall(array($value), $objectsPool, $refsPool, $objectsCount, $isStaticValue)[0];
|
||||||
|
} finally {
|
||||||
|
$references = array();
|
||||||
|
foreach ($refsPool as $i => $v) {
|
||||||
|
$v[0] = $v[1];
|
||||||
|
$references[1 + $i] = $v[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($isStaticValue) {
|
||||||
|
return var_export($value, true);
|
||||||
|
}
|
||||||
|
|
||||||
$classes = array();
|
$classes = array();
|
||||||
$values = array();
|
$values = array();
|
||||||
|
@ -46,6 +65,7 @@ class PhpMarshaller
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ksort($wakeups);
|
ksort($wakeups);
|
||||||
|
|
||||||
$properties = array();
|
$properties = array();
|
||||||
foreach ($values as $i => $vars) {
|
foreach ($values as $i => $vars) {
|
||||||
foreach ($vars as $class => $values) {
|
foreach ($vars as $class => $values) {
|
||||||
|
@ -54,131 +74,14 @@ class PhpMarshaller
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!$classes) {
|
|
||||||
return $value[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Configurator(new Registry($classes), $properties, $value[0], $wakeups);
|
$value = new Configurator($classes ? new Registry($classes) : null, $references ? new Values($references) : null, $properties, $value, $wakeups);
|
||||||
}
|
$value = var_export($value, true);
|
||||||
|
|
||||||
public static function optimize(string $exportedValue)
|
$regexp = sprintf("{%s::__set_state\(array\(\s++'id' => %%s(\d+),\s++\)\)}", preg_quote(Reference::class));
|
||||||
{
|
$value = preg_replace(sprintf($regexp, ''), Registry::class.'::$objects[$1]', $value);
|
||||||
return preg_replace(sprintf("{%s::__set_state\(array\(\s++'0' => (\d+),\s++\)\)}", preg_quote(Reference::class)), Registry::class.'::$objects[$1]', $exportedValue);
|
$value = preg_replace(sprintf($regexp, '-'), '&'.Registry::class.'::$references[$1]', $value);
|
||||||
}
|
|
||||||
|
|
||||||
private static function doMarshall(array &$array, \SplObjectStorage $objectsPool): int
|
return $value;
|
||||||
{
|
|
||||||
$objectsCount = 0;
|
|
||||||
|
|
||||||
foreach ($array as &$value) {
|
|
||||||
if (\is_array($value) && $value) {
|
|
||||||
$objectsCount += self::doMarshall($value, $objectsPool);
|
|
||||||
}
|
|
||||||
if (!\is_object($value)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (isset($objectsPool[$value])) {
|
|
||||||
++$objectsCount;
|
|
||||||
$value = new Reference($objectsPool[$value][0]);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$class = \get_class($value);
|
|
||||||
$properties = array();
|
|
||||||
$sleep = null;
|
|
||||||
$arrayValue = (array) $value;
|
|
||||||
$proto = (Registry::$reflectors[$class] ?? Registry::getClassReflector($class))->newInstanceWithoutConstructor();
|
|
||||||
|
|
||||||
if ($value instanceof \ArrayIterator || $value instanceof \ArrayObject) {
|
|
||||||
// ArrayIterator and ArrayObject need special care because their "flags"
|
|
||||||
// option changes the behavior of the (array) casting operator.
|
|
||||||
$reflector = $value instanceof \ArrayIterator ? 'ArrayIterator' : 'ArrayObject';
|
|
||||||
$reflector = Registry::$reflectors[$reflector] ?? Registry::getClassReflector($reflector);
|
|
||||||
|
|
||||||
$properties = array(
|
|
||||||
$arrayValue,
|
|
||||||
$reflector->getMethod('getFlags')->invoke($value),
|
|
||||||
$value instanceof \ArrayObject ? $reflector->getMethod('getIteratorClass')->invoke($value) : 'ArrayIterator',
|
|
||||||
);
|
|
||||||
|
|
||||||
$reflector = $reflector->getMethod('setFlags');
|
|
||||||
$reflector->invoke($proto, \ArrayObject::STD_PROP_LIST);
|
|
||||||
|
|
||||||
if ($properties[1] & \ArrayObject::STD_PROP_LIST) {
|
|
||||||
$reflector->invoke($value, 0);
|
|
||||||
$properties[0] = (array) $value;
|
|
||||||
} else {
|
|
||||||
$reflector->invoke($value, \ArrayObject::STD_PROP_LIST);
|
|
||||||
$arrayValue = (array) $value;
|
|
||||||
}
|
|
||||||
$reflector->invoke($value, $properties[1]);
|
|
||||||
|
|
||||||
if (array(array(), 0, 'ArrayIterator') === $properties) {
|
|
||||||
$properties = array();
|
|
||||||
} else {
|
|
||||||
if ('ArrayIterator' === $properties[2]) {
|
|
||||||
unset($properties[2]);
|
|
||||||
}
|
|
||||||
$properties = array($reflector->class => array("\0" => $properties));
|
|
||||||
}
|
|
||||||
} elseif ($value instanceof \SplObjectStorage) {
|
|
||||||
foreach (clone $value as $v) {
|
|
||||||
$properties[] = $v;
|
|
||||||
$properties[] = $value[$v];
|
|
||||||
}
|
|
||||||
$properties = array('SplObjectStorage' => array("\0" => $properties));
|
|
||||||
} elseif ($value instanceof \Serializable) {
|
|
||||||
++$objectsCount;
|
|
||||||
$objectsPool[$value] = array($id = \count($objectsPool), serialize($value), array(), 0);
|
|
||||||
$value = new Reference($id);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (\method_exists($class, '__sleep')) {
|
|
||||||
if (!\is_array($sleep = $value->__sleep())) {
|
|
||||||
trigger_error('serialize(): __sleep should return an array only containing the names of instance-variables to serialize', E_USER_NOTICE);
|
|
||||||
$value = null;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$sleep = array_flip($sleep);
|
|
||||||
}
|
|
||||||
|
|
||||||
$proto = (array) $proto;
|
|
||||||
|
|
||||||
foreach ($arrayValue as $name => $v) {
|
|
||||||
$k = (string) $name;
|
|
||||||
if ('' === $k || "\0" !== $k[0]) {
|
|
||||||
$c = $class;
|
|
||||||
} elseif ('*' === $k[1]) {
|
|
||||||
$c = $class;
|
|
||||||
$k = substr($k, 3);
|
|
||||||
} else {
|
|
||||||
$i = strpos($k, "\0", 2);
|
|
||||||
$c = substr($k, 1, $i - 1);
|
|
||||||
$k = substr($k, 1 + $i);
|
|
||||||
}
|
|
||||||
if (null === $sleep) {
|
|
||||||
$properties[$c][$k] = $v;
|
|
||||||
} elseif (isset($sleep[$k]) && $c === $class) {
|
|
||||||
$properties[$c][$k] = $v;
|
|
||||||
unset($sleep[$k]);
|
|
||||||
}
|
|
||||||
if (\array_key_exists($name, $proto) && $proto[$name] === $v) {
|
|
||||||
unset($properties[$c][$k]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($sleep) {
|
|
||||||
foreach ($sleep as $k => $v) {
|
|
||||||
trigger_error(sprintf('serialize(): "%s" returned as member variable from __sleep() but does not exist', $k), E_USER_NOTICE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$objectsPool[$value] = array($id = \count($objectsPool));
|
|
||||||
$objectsCount += 1 + self::doMarshall($properties, $objectsPool);
|
|
||||||
$objectsPool[$value] = array($id, $class, $properties, \method_exists($class, '__wakeup') ? $objectsCount : 0);
|
|
||||||
|
|
||||||
$value = new Reference($id);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $objectsCount;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,19 +20,20 @@ class Configurator
|
||||||
{
|
{
|
||||||
public static $configurators = array();
|
public static $configurators = array();
|
||||||
|
|
||||||
public function __construct(Registry $registry, array $properties, $value, array $wakeups)
|
public function __construct(?Registry $registry, ?Values $values, array $properties, $value, array $wakeups)
|
||||||
{
|
{
|
||||||
$this->{0} = $registry;
|
$this->{0} = $registry;
|
||||||
$this->{1} = $properties;
|
$this->{1} = $values;
|
||||||
$this->{2} = $value;
|
$this->{2} = $properties;
|
||||||
$this->{3} = $wakeups;
|
$this->{3} = $value;
|
||||||
|
$this->{4} = $wakeups;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function __set_state($state)
|
public static function __set_state($state)
|
||||||
{
|
{
|
||||||
$objects = Registry::$objects;
|
$objects = Registry::$objects;
|
||||||
Registry::$objects = \array_pop(Registry::$stack);
|
list(Registry::$objects, Registry::$references) = \array_pop(Registry::$stack);
|
||||||
list(, $properties, $value, $wakeups) = $state;
|
list(, , $properties, $value, $wakeups) = $state;
|
||||||
|
|
||||||
foreach ($properties as $class => $vars) {
|
foreach ($properties as $class => $vars) {
|
||||||
(self::$configurators[$class] ?? self::getConfigurator($class))($vars, $objects);
|
(self::$configurators[$class] ?? self::getConfigurator($class))($vars, $objects);
|
||||||
|
|
|
@ -0,0 +1,212 @@
|
||||||
|
<?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\Marshaller\PhpMarshaller;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Nicolas Grekas <p@tchwork.com>
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
class Marshaller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Prepares an array of values for PhpMarshaller.
|
||||||
|
*
|
||||||
|
* For performance this method is public and has no type-hints.
|
||||||
|
*
|
||||||
|
* @param array &$values
|
||||||
|
* @param \SplObjectStorage $objectsPool
|
||||||
|
* @param array &$refsPool
|
||||||
|
* @param int &$objectsCount
|
||||||
|
* @param bool &$valuesAreStatic
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*
|
||||||
|
* @throws \Exception When a value cannot be serialized
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
public static function marshall($values, $objectsPool, &$refsPool, &$objectsCount, &$valuesAreStatic)
|
||||||
|
{
|
||||||
|
$refs = $values;
|
||||||
|
foreach ($values as $k => $value) {
|
||||||
|
if (\is_resource($value)) {
|
||||||
|
throw new \Exception(sprintf("Serialization of '%s' resource is not allowed", \get_resource_type($value)));
|
||||||
|
}
|
||||||
|
$refs[$k] = $objectsPool;
|
||||||
|
|
||||||
|
if ($isRef = !$valueIsStatic = $values[$k] !== $objectsPool) {
|
||||||
|
$values[$k] = &$value; // Break hard references to make $values completely
|
||||||
|
unset($value); // independent from the original structure
|
||||||
|
$refs[$k] = $value = $values[$k];
|
||||||
|
if ($value instanceof Reference && 0 > $value->id) {
|
||||||
|
$valuesAreStatic = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$refsPool[] = array(&$refs[$k], $value, &$value);
|
||||||
|
$refs[$k] = $values[$k] = new Reference(-\count($refsPool));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (\is_array($value)) {
|
||||||
|
if ($value) {
|
||||||
|
$value = self::marshall($value, $objectsPool, $refsPool, $objectsCount, $valueIsStatic);
|
||||||
|
}
|
||||||
|
goto handle_value;
|
||||||
|
} elseif (!\is_object($value) && !$value instanceof \__PHP_Incomplete_Class) {
|
||||||
|
goto handle_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
$valueIsStatic = false;
|
||||||
|
if (isset($objectsPool[$value])) {
|
||||||
|
++$objectsCount;
|
||||||
|
$value = new Reference($objectsPool[$value][0]);
|
||||||
|
goto handle_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
$class = \get_class($value);
|
||||||
|
$properties = array();
|
||||||
|
$sleep = null;
|
||||||
|
$arrayValue = (array) $value;
|
||||||
|
|
||||||
|
if (!isset(Registry::$prototypes[$class])) {
|
||||||
|
// Might throw Exception("Serialization of '...' is not allowed")
|
||||||
|
Registry::getClassReflector($class);
|
||||||
|
serialize(Registry::$prototypes[$class]);
|
||||||
|
}
|
||||||
|
$proto = Registry::$prototypes[$class];
|
||||||
|
|
||||||
|
if ($value instanceof \ArrayIterator || $value instanceof \ArrayObject) {
|
||||||
|
// ArrayIterator and ArrayObject need special care because their "flags"
|
||||||
|
// option changes the behavior of the (array) casting operator.
|
||||||
|
$proto = Registry::$cloneable[$class] ? clone Registry::$prototypes[$class] : Registry::$reflectors[$class]->newInstanceWithoutConstructor();
|
||||||
|
$properties = self::getArrayObjectProperties($value, $arrayValue, $proto);
|
||||||
|
} elseif ($value instanceof \SplObjectStorage) {
|
||||||
|
// By implementing Serializable, SplObjectStorage breaks internal references,
|
||||||
|
// let's deal with it on our own.
|
||||||
|
foreach (clone $value as $v) {
|
||||||
|
$properties[] = $v;
|
||||||
|
$properties[] = $value[$v];
|
||||||
|
}
|
||||||
|
$properties = array('SplObjectStorage' => array("\0" => $properties));
|
||||||
|
} elseif ($value instanceof \Serializable || $value instanceof \__PHP_Incomplete_Class) {
|
||||||
|
++$objectsCount;
|
||||||
|
$objectsPool[$value] = array($id = \count($objectsPool), serialize($value), array(), 0);
|
||||||
|
$value = new Reference($id);
|
||||||
|
goto handle_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (\method_exists($class, '__sleep')) {
|
||||||
|
if (!\is_array($sleep = $value->__sleep())) {
|
||||||
|
trigger_error('serialize(): __sleep should return an array only containing the names of instance-variables to serialize', E_USER_NOTICE);
|
||||||
|
$value = null;
|
||||||
|
goto handle_value;
|
||||||
|
}
|
||||||
|
$sleep = array_flip($sleep);
|
||||||
|
}
|
||||||
|
|
||||||
|
$proto = (array) $proto;
|
||||||
|
|
||||||
|
foreach ($arrayValue as $name => $v) {
|
||||||
|
$n = (string) $name;
|
||||||
|
if ('' === $n || "\0" !== $n[0]) {
|
||||||
|
$c = $class;
|
||||||
|
} elseif ('*' === $n[1]) {
|
||||||
|
$c = $class;
|
||||||
|
$n = substr($n, 3);
|
||||||
|
} else {
|
||||||
|
$i = strpos($n, "\0", 2);
|
||||||
|
$c = substr($n, 1, $i - 1);
|
||||||
|
$n = substr($n, 1 + $i);
|
||||||
|
}
|
||||||
|
if (null === $sleep) {
|
||||||
|
$properties[$c][$n] = $v;
|
||||||
|
} elseif (isset($sleep[$n]) && $c === $class) {
|
||||||
|
$properties[$c][$n] = $v;
|
||||||
|
unset($sleep[$n]);
|
||||||
|
}
|
||||||
|
if (\array_key_exists($name, $proto) && $proto[$name] === $v) {
|
||||||
|
unset($properties[$c][$n]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($sleep) {
|
||||||
|
foreach ($sleep as $n => $v) {
|
||||||
|
trigger_error(sprintf('serialize(): "%s" returned as member variable from __sleep() but does not exist', $n), E_USER_NOTICE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$objectsPool[$value] = array($id = \count($objectsPool));
|
||||||
|
$properties = self::marshall($properties, $objectsPool, $refsPool, $objectsCount, $valueIsStatic);
|
||||||
|
++$objectsCount;
|
||||||
|
$objectsPool[$value] = array($id, $class, $properties, \method_exists($class, '__wakeup') ? $objectsCount : 0);
|
||||||
|
|
||||||
|
$value = new Reference($id);
|
||||||
|
|
||||||
|
handle_value:
|
||||||
|
if ($isRef) {
|
||||||
|
unset($value); // Break the hard reference created above
|
||||||
|
} elseif (!$valueIsStatic) {
|
||||||
|
$values[$k] = $value;
|
||||||
|
}
|
||||||
|
$valuesAreStatic = $valueIsStatic && $valuesAreStatic;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $values;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the state of an ArrayIterator or ArrayObject instance.
|
||||||
|
*
|
||||||
|
* For performance this method is public and has no type-hints.
|
||||||
|
*
|
||||||
|
* @param \ArrayIterator|\ArrayObject $value
|
||||||
|
* @param array &$arrayValue
|
||||||
|
* @param object $proto
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
public static function getArrayObjectProperties($value, &$arrayValue, $proto)
|
||||||
|
{
|
||||||
|
$reflector = $value instanceof \ArrayIterator ? 'ArrayIterator' : 'ArrayObject';
|
||||||
|
$reflector = Registry::$reflectors[$reflector] ?? Registry::getClassReflector($reflector);
|
||||||
|
|
||||||
|
$properties = array(
|
||||||
|
$arrayValue,
|
||||||
|
$reflector->getMethod('getFlags')->invoke($value),
|
||||||
|
$value instanceof \ArrayObject ? $reflector->getMethod('getIteratorClass')->invoke($value) : 'ArrayIterator',
|
||||||
|
);
|
||||||
|
|
||||||
|
$reflector = $reflector->getMethod('setFlags');
|
||||||
|
$reflector->invoke($proto, \ArrayObject::STD_PROP_LIST);
|
||||||
|
|
||||||
|
if ($properties[1] & \ArrayObject::STD_PROP_LIST) {
|
||||||
|
$reflector->invoke($value, 0);
|
||||||
|
$properties[0] = (array) $value;
|
||||||
|
} else {
|
||||||
|
$reflector->invoke($value, \ArrayObject::STD_PROP_LIST);
|
||||||
|
$arrayValue = (array) $value;
|
||||||
|
}
|
||||||
|
$reflector->invoke($value, $properties[1]);
|
||||||
|
|
||||||
|
if (array(array(), 0, 'ArrayIterator') === $properties) {
|
||||||
|
$properties = array();
|
||||||
|
} else {
|
||||||
|
if ('ArrayIterator' === $properties[2]) {
|
||||||
|
unset($properties[2]);
|
||||||
|
}
|
||||||
|
$properties = array($reflector->class => array("\0" => $properties));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $properties;
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,13 +18,10 @@ namespace Symfony\Component\Cache\Marshaller\PhpMarshaller;
|
||||||
*/
|
*/
|
||||||
class Reference
|
class Reference
|
||||||
{
|
{
|
||||||
|
public $id;
|
||||||
|
|
||||||
public function __construct(int $id)
|
public function __construct(int $id)
|
||||||
{
|
{
|
||||||
$this->{0} = $id;
|
$this->id = $id;
|
||||||
}
|
|
||||||
|
|
||||||
public static function __set_state($state)
|
|
||||||
{
|
|
||||||
return Registry::$objects[$state[0]];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,8 +20,11 @@ class Registry
|
||||||
{
|
{
|
||||||
public static $stack = array();
|
public static $stack = array();
|
||||||
public static $objects = array();
|
public static $objects = array();
|
||||||
|
public static $references = array();
|
||||||
public static $reflectors = array();
|
public static $reflectors = array();
|
||||||
public static $prototypes = array();
|
public static $prototypes = array();
|
||||||
|
public static $cloneable = array();
|
||||||
|
public static $instantiableWithoutConstructor = array();
|
||||||
|
|
||||||
public function __construct(array $classes)
|
public function __construct(array $classes)
|
||||||
{
|
{
|
||||||
|
@ -32,15 +35,33 @@ class Registry
|
||||||
|
|
||||||
public static function __set_state($classes)
|
public static function __set_state($classes)
|
||||||
{
|
{
|
||||||
self::$stack[] = self::$objects;
|
$unserializeCallback = null;
|
||||||
|
self::$stack[] = array(self::$objects, self::$references);
|
||||||
self::$objects = $classes;
|
self::$objects = $classes;
|
||||||
foreach (self::$objects as &$class) {
|
self::$references = array();
|
||||||
if (isset(self::$prototypes[$class])) {
|
try {
|
||||||
$class = clone self::$prototypes[$class];
|
foreach (self::$objects as &$class) {
|
||||||
} elseif (':' === ($class[1] ?? null)) {
|
if (':' === ($class[1] ?? null)) {
|
||||||
$class = \unserialize($class);
|
if (null === $unserializeCallback) {
|
||||||
} else {
|
$unserializeCallback = ini_set('unserialize_callback_func', __CLASS__.'::getClassReflector');
|
||||||
$class = (self::$reflectors[$class] ?? self::getClassReflector($class))->newInstanceWithoutConstructor();
|
}
|
||||||
|
$class = \unserialize($class);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$r = self::$reflectors[$class] ?? self::getClassReflector($class);
|
||||||
|
|
||||||
|
if (self::$cloneable[$class]) {
|
||||||
|
$class = clone self::$prototypes[$class];
|
||||||
|
} else {
|
||||||
|
$class = self::$instantiableWithoutConstructor[$class] ? $r->newInstanceWithoutConstructor() : $r->newInstance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
list(self::$objects, self::$references) = \array_pop(self::$stack);
|
||||||
|
throw $e;
|
||||||
|
} finally {
|
||||||
|
if (null !== $unserializeCallback) {
|
||||||
|
ini_set('unserialize_callback_func', $unserializeCallback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,8 +70,38 @@ class Registry
|
||||||
{
|
{
|
||||||
$reflector = new \ReflectionClass($class);
|
$reflector = new \ReflectionClass($class);
|
||||||
|
|
||||||
if (!$reflector->hasMethod('__clone')) {
|
if (self::$instantiableWithoutConstructor[$class] = !$reflector->isFinal() || !$reflector->isInternal()) {
|
||||||
self::$prototypes[$class] = $reflector->newInstanceWithoutConstructor();
|
$proto = $reflector->newInstanceWithoutConstructor();
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
$proto = $reflector->newInstance();
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
throw new \Exception(sprintf("Serialization of '%s' is not allowed", $class), 0, $e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($proto instanceof \Reflector || $proto instanceof \ReflectionGenerator || $proto instanceof \ReflectionType) {
|
||||||
|
if (!$proto instanceof \Serializable && !\method_exists($proto, '__wakeup')) {
|
||||||
|
throw new \Exception(sprintf("Serialization of '%s' is not allowed", $class));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self::$prototypes[$class] = $proto;
|
||||||
|
self::$cloneable[$class] = !$reflector->hasMethod('__clone');
|
||||||
|
|
||||||
|
if ($proto instanceof \Throwable) {
|
||||||
|
static $trace;
|
||||||
|
|
||||||
|
if (null === $trace) {
|
||||||
|
$trace = array(
|
||||||
|
new \ReflectionProperty(\Error::class, 'trace'),
|
||||||
|
new \ReflectionProperty(\Exception::class, 'trace'),
|
||||||
|
);
|
||||||
|
$trace[0]->setAccessible(true);
|
||||||
|
$trace[1]->setAccessible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
$trace[$proto instanceof \Exception]->setValue($proto, array());
|
||||||
}
|
}
|
||||||
|
|
||||||
return self::$reflectors[$class] = $reflector;
|
return self::$reflectors[$class] = $reflector;
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
<?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\Marshaller\PhpMarshaller;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Nicolas Grekas <p@tchwork.com>
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
class Values
|
||||||
|
{
|
||||||
|
public function __construct(array $values)
|
||||||
|
{
|
||||||
|
foreach ($values as $i => $v) {
|
||||||
|
$this->$i = $v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function __set_state($values)
|
||||||
|
{
|
||||||
|
foreach ($values as $i => $v) {
|
||||||
|
Registry::$references[$i] = $v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,7 +13,6 @@ namespace Symfony\Component\Cache\Simple;
|
||||||
|
|
||||||
use Psr\SimpleCache\CacheInterface;
|
use Psr\SimpleCache\CacheInterface;
|
||||||
use Symfony\Component\Cache\Exception\InvalidArgumentException;
|
use Symfony\Component\Cache\Exception\InvalidArgumentException;
|
||||||
use Symfony\Component\Cache\Marshaller\DefaultMarshaller;
|
|
||||||
use Symfony\Component\Cache\PruneableInterface;
|
use Symfony\Component\Cache\PruneableInterface;
|
||||||
use Symfony\Component\Cache\ResettableInterface;
|
use Symfony\Component\Cache\ResettableInterface;
|
||||||
use Symfony\Component\Cache\Traits\PhpArrayTrait;
|
use Symfony\Component\Cache\Traits\PhpArrayTrait;
|
||||||
|
@ -29,8 +28,6 @@ class PhpArrayCache implements CacheInterface, PruneableInterface, ResettableInt
|
||||||
{
|
{
|
||||||
use PhpArrayTrait;
|
use PhpArrayTrait;
|
||||||
|
|
||||||
private $marshaller;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $file The PHP file were values are cached
|
* @param string $file The PHP file were values are cached
|
||||||
* @param CacheInterface $fallbackPool A pool to fallback on when an item is not hit
|
* @param CacheInterface $fallbackPool A pool to fallback on when an item is not hit
|
||||||
|
@ -84,13 +81,6 @@ class PhpArrayCache implements CacheInterface, PruneableInterface, ResettableInt
|
||||||
return $default;
|
return $default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (\is_string($value) && isset($value[2]) && ':' === $value[1]) {
|
|
||||||
try {
|
|
||||||
return ($this->marshaller ?? $this->marshaller = new DefaultMarshaller())->unmarshall($value);
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
return $default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $value;
|
return $value;
|
||||||
}
|
}
|
||||||
|
@ -243,12 +233,6 @@ class PhpArrayCache implements CacheInterface, PruneableInterface, ResettableInt
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
yield $key => $default;
|
yield $key => $default;
|
||||||
}
|
}
|
||||||
} elseif (\is_string($value) && isset($value[2]) && ':' === $value[1]) {
|
|
||||||
try {
|
|
||||||
yield $key => unserialize($value);
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
yield $key => $default;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
yield $key => $value;
|
yield $key => $value;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::__set_state(array(
|
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::__set_state(array(
|
||||||
'0' => 'ArrayIterator',
|
'0' => 'ArrayIterator',
|
||||||
)),
|
)),
|
||||||
'1' =>
|
'1' => NULL,
|
||||||
|
'2' =>
|
||||||
array (
|
array (
|
||||||
'ArrayIterator' =>
|
'ArrayIterator' =>
|
||||||
array (
|
array (
|
||||||
|
@ -20,11 +21,9 @@
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
'2' =>
|
|
||||||
Symfony\Component\Cache\Marshaller\PhpMarshaller\Reference::__set_state(array(
|
|
||||||
'0' => 0,
|
|
||||||
)),
|
|
||||||
'3' =>
|
'3' =>
|
||||||
|
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::$objects[0],
|
||||||
|
'4' =>
|
||||||
array (
|
array (
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
<?php return Symfony\Component\Cache\Marshaller\PhpMarshaller\Configurator::__set_state(array(
|
|
||||||
'0' =>
|
|
||||||
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::__set_state(array(
|
|
||||||
'0' => 'Symfony\\Component\\Cache\\Tests\\Marshaller\\MyArrayObject',
|
|
||||||
)),
|
|
||||||
'1' =>
|
|
||||||
array (
|
|
||||||
'ArrayObject' =>
|
|
||||||
array (
|
|
||||||
'' . "\0" . '' =>
|
|
||||||
array (
|
|
||||||
0 =>
|
|
||||||
array (
|
|
||||||
0 =>
|
|
||||||
array (
|
|
||||||
0 => 234,
|
|
||||||
),
|
|
||||||
1 => 1,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
'2' =>
|
|
||||||
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::$objects[0],
|
|
||||||
'3' =>
|
|
||||||
array (
|
|
||||||
),
|
|
||||||
));
|
|
|
@ -3,7 +3,8 @@
|
||||||
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::__set_state(array(
|
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::__set_state(array(
|
||||||
'0' => 'Symfony\\Component\\Cache\\Tests\\Marshaller\\MyArrayObject',
|
'0' => 'Symfony\\Component\\Cache\\Tests\\Marshaller\\MyArrayObject',
|
||||||
)),
|
)),
|
||||||
'1' =>
|
'1' => NULL,
|
||||||
|
'2' =>
|
||||||
array (
|
array (
|
||||||
'ArrayObject' =>
|
'ArrayObject' =>
|
||||||
array (
|
array (
|
||||||
|
@ -20,11 +21,9 @@
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
'2' =>
|
|
||||||
Symfony\Component\Cache\Marshaller\PhpMarshaller\Reference::__set_state(array(
|
|
||||||
'0' => 0,
|
|
||||||
)),
|
|
||||||
'3' =>
|
'3' =>
|
||||||
|
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::$objects[0],
|
||||||
|
'4' =>
|
||||||
array (
|
array (
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
<?php return Symfony\Component\Cache\Marshaller\PhpMarshaller\Configurator::__set_state(array(
|
|
||||||
'0' =>
|
|
||||||
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::__set_state(array(
|
|
||||||
'0' => 'ArrayObject',
|
|
||||||
'1' => 'ArrayObject',
|
|
||||||
)),
|
|
||||||
'1' =>
|
|
||||||
array (
|
|
||||||
'ArrayObject' =>
|
|
||||||
array (
|
|
||||||
'' . "\0" . '' =>
|
|
||||||
array (
|
|
||||||
0 =>
|
|
||||||
array (
|
|
||||||
0 =>
|
|
||||||
array (
|
|
||||||
0 => 1,
|
|
||||||
1 =>
|
|
||||||
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::$objects[0],
|
|
||||||
),
|
|
||||||
1 => 0,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
'foo' =>
|
|
||||||
array (
|
|
||||||
0 =>
|
|
||||||
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::$objects[1],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
'2' =>
|
|
||||||
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::$objects[0],
|
|
||||||
'3' =>
|
|
||||||
array (
|
|
||||||
),
|
|
||||||
));
|
|
|
@ -4,7 +4,8 @@
|
||||||
'0' => 'ArrayObject',
|
'0' => 'ArrayObject',
|
||||||
'1' => 'ArrayObject',
|
'1' => 'ArrayObject',
|
||||||
)),
|
)),
|
||||||
'1' =>
|
'1' => NULL,
|
||||||
|
'2' =>
|
||||||
array (
|
array (
|
||||||
'ArrayObject' =>
|
'ArrayObject' =>
|
||||||
array (
|
array (
|
||||||
|
@ -16,9 +17,7 @@
|
||||||
array (
|
array (
|
||||||
0 => 1,
|
0 => 1,
|
||||||
1 =>
|
1 =>
|
||||||
Symfony\Component\Cache\Marshaller\PhpMarshaller\Reference::__set_state(array(
|
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::$objects[0],
|
||||||
'0' => 0,
|
|
||||||
)),
|
|
||||||
),
|
),
|
||||||
1 => 0,
|
1 => 0,
|
||||||
),
|
),
|
||||||
|
@ -26,17 +25,13 @@
|
||||||
'foo' =>
|
'foo' =>
|
||||||
array (
|
array (
|
||||||
0 =>
|
0 =>
|
||||||
Symfony\Component\Cache\Marshaller\PhpMarshaller\Reference::__set_state(array(
|
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::$objects[1],
|
||||||
'0' => 1,
|
|
||||||
)),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
'2' =>
|
|
||||||
Symfony\Component\Cache\Marshaller\PhpMarshaller\Reference::__set_state(array(
|
|
||||||
'0' => 0,
|
|
||||||
)),
|
|
||||||
'3' =>
|
'3' =>
|
||||||
|
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::$objects[0],
|
||||||
|
'4' =>
|
||||||
array (
|
array (
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
<?php return Symfony\Component\Cache\Marshaller\PhpMarshaller\Configurator::__set_state(array(
|
|
||||||
'0' =>
|
|
||||||
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::__set_state(array(
|
|
||||||
'0' => 'Symfony\\Component\\Cache\\Tests\\Marshaller\\MyCloneable',
|
|
||||||
'1' => 'Symfony\\Component\\Cache\\Tests\\Marshaller\\MyNotCloneable',
|
|
||||||
)),
|
|
||||||
'1' =>
|
|
||||||
array (
|
|
||||||
),
|
|
||||||
'2' =>
|
|
||||||
array (
|
|
||||||
0 =>
|
|
||||||
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::$objects[0],
|
|
||||||
1 =>
|
|
||||||
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::$objects[1],
|
|
||||||
),
|
|
||||||
'3' =>
|
|
||||||
array (
|
|
||||||
),
|
|
||||||
));
|
|
|
@ -4,21 +4,18 @@
|
||||||
'0' => 'Symfony\\Component\\Cache\\Tests\\Marshaller\\MyCloneable',
|
'0' => 'Symfony\\Component\\Cache\\Tests\\Marshaller\\MyCloneable',
|
||||||
'1' => 'Symfony\\Component\\Cache\\Tests\\Marshaller\\MyNotCloneable',
|
'1' => 'Symfony\\Component\\Cache\\Tests\\Marshaller\\MyNotCloneable',
|
||||||
)),
|
)),
|
||||||
'1' =>
|
'1' => NULL,
|
||||||
array (
|
|
||||||
),
|
|
||||||
'2' =>
|
'2' =>
|
||||||
array (
|
array (
|
||||||
0 =>
|
|
||||||
Symfony\Component\Cache\Marshaller\PhpMarshaller\Reference::__set_state(array(
|
|
||||||
'0' => 0,
|
|
||||||
)),
|
|
||||||
1 =>
|
|
||||||
Symfony\Component\Cache\Marshaller\PhpMarshaller\Reference::__set_state(array(
|
|
||||||
'0' => 1,
|
|
||||||
)),
|
|
||||||
),
|
),
|
||||||
'3' =>
|
'3' =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::$objects[0],
|
||||||
|
1 =>
|
||||||
|
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::$objects[1],
|
||||||
|
),
|
||||||
|
'4' =>
|
||||||
array (
|
array (
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
<?php return Symfony\Component\Cache\Marshaller\PhpMarshaller\Configurator::__set_state(array(
|
|
||||||
'0' =>
|
|
||||||
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::__set_state(array(
|
|
||||||
'0' => 'DateTime',
|
|
||||||
)),
|
|
||||||
'1' =>
|
|
||||||
array (
|
|
||||||
'DateTime' =>
|
|
||||||
array (
|
|
||||||
'date' =>
|
|
||||||
array (
|
|
||||||
0 => '1970-01-01 00:00:00.000000',
|
|
||||||
),
|
|
||||||
'timezone_type' =>
|
|
||||||
array (
|
|
||||||
0 => 1,
|
|
||||||
),
|
|
||||||
'timezone' =>
|
|
||||||
array (
|
|
||||||
0 => '+00:00',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
'2' =>
|
|
||||||
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::$objects[0],
|
|
||||||
'3' =>
|
|
||||||
array (
|
|
||||||
1 => 0,
|
|
||||||
),
|
|
||||||
));
|
|
|
@ -3,7 +3,8 @@
|
||||||
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::__set_state(array(
|
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::__set_state(array(
|
||||||
'0' => 'DateTime',
|
'0' => 'DateTime',
|
||||||
)),
|
)),
|
||||||
'1' =>
|
'1' => NULL,
|
||||||
|
'2' =>
|
||||||
array (
|
array (
|
||||||
'DateTime' =>
|
'DateTime' =>
|
||||||
array (
|
array (
|
||||||
|
@ -21,11 +22,9 @@
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
'2' =>
|
|
||||||
Symfony\Component\Cache\Marshaller\PhpMarshaller\Reference::__set_state(array(
|
|
||||||
'0' => 0,
|
|
||||||
)),
|
|
||||||
'3' =>
|
'3' =>
|
||||||
|
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::$objects[0],
|
||||||
|
'4' =>
|
||||||
array (
|
array (
|
||||||
1 => 0,
|
1 => 0,
|
||||||
),
|
),
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?php return Symfony\Component\Cache\Marshaller\PhpMarshaller\Configurator::__set_state(array(
|
||||||
|
'0' => NULL,
|
||||||
|
'1' =>
|
||||||
|
Symfony\Component\Cache\Marshaller\PhpMarshaller\Values::__set_state(array(
|
||||||
|
'1' =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
&Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::$references[1],
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
'2' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'3' =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
&Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::$references[1],
|
||||||
|
),
|
||||||
|
'4' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
));
|
|
@ -1,19 +1,26 @@
|
||||||
<?php return Symfony\Component\Cache\Marshaller\PhpMarshaller\Configurator::__set_state(array(
|
<?php return Symfony\Component\Cache\Marshaller\PhpMarshaller\Configurator::__set_state(array(
|
||||||
'0' =>
|
'0' =>
|
||||||
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::__set_state(array(
|
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::__set_state(array(
|
||||||
'0' => 'C:55:"Symfony\\Component\\Cache\\Tests\\Marshaller\\MySerializable":3:{123}',
|
'0' => 'stdClass',
|
||||||
)),
|
)),
|
||||||
'1' =>
|
'1' =>
|
||||||
array (
|
Symfony\Component\Cache\Marshaller\PhpMarshaller\Values::__set_state(array(
|
||||||
),
|
'1' =>
|
||||||
|
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::$objects[0],
|
||||||
|
)),
|
||||||
'2' =>
|
'2' =>
|
||||||
array (
|
array (
|
||||||
0 =>
|
|
||||||
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::$objects[0],
|
|
||||||
1 =>
|
|
||||||
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::$objects[0],
|
|
||||||
),
|
),
|
||||||
'3' =>
|
'3' =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
&Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::$references[1],
|
||||||
|
1 =>
|
||||||
|
&Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::$references[1],
|
||||||
|
2 =>
|
||||||
|
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::$objects[0],
|
||||||
|
),
|
||||||
|
'4' =>
|
||||||
array (
|
array (
|
||||||
),
|
),
|
||||||
));
|
));
|
|
@ -1,28 +1,15 @@
|
||||||
<?php return Symfony\Component\Cache\Marshaller\PhpMarshaller\Configurator::__set_state(array(
|
<?php return Symfony\Component\Cache\Marshaller\PhpMarshaller\Configurator::__set_state(array(
|
||||||
'0' =>
|
'0' =>
|
||||||
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::__set_state(array(
|
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::__set_state(array(
|
||||||
'0' => 'ArrayIterator',
|
'0' => 'O:20:"SomeNotExistingClass":0:{}',
|
||||||
)),
|
)),
|
||||||
'1' =>
|
'1' => NULL,
|
||||||
array (
|
|
||||||
'ArrayIterator' =>
|
|
||||||
array (
|
|
||||||
'' . "\0" . '' =>
|
|
||||||
array (
|
|
||||||
0 =>
|
|
||||||
array (
|
|
||||||
0 =>
|
|
||||||
array (
|
|
||||||
0 => 123,
|
|
||||||
),
|
|
||||||
1 => 1,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
'2' =>
|
'2' =>
|
||||||
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::$objects[0],
|
array (
|
||||||
|
),
|
||||||
'3' =>
|
'3' =>
|
||||||
|
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::$objects[0],
|
||||||
|
'4' =>
|
||||||
array (
|
array (
|
||||||
),
|
),
|
||||||
));
|
));
|
|
@ -1,39 +0,0 @@
|
||||||
<?php return Symfony\Component\Cache\Marshaller\PhpMarshaller\Configurator::__set_state(array(
|
|
||||||
'0' =>
|
|
||||||
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::__set_state(array(
|
|
||||||
'0' => 'Symfony\\Component\\Cache\\Tests\\Marshaller\\MyPrivateValue',
|
|
||||||
'1' => 'Symfony\\Component\\Cache\\Tests\\Marshaller\\MyPrivateChildValue',
|
|
||||||
)),
|
|
||||||
'1' =>
|
|
||||||
array (
|
|
||||||
'Symfony\\Component\\Cache\\Tests\\Marshaller\\MyPrivateValue' =>
|
|
||||||
array (
|
|
||||||
'prot' =>
|
|
||||||
array (
|
|
||||||
0 => 123,
|
|
||||||
),
|
|
||||||
'priv' =>
|
|
||||||
array (
|
|
||||||
0 => 234,
|
|
||||||
1 => 234,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
'Symfony\\Component\\Cache\\Tests\\Marshaller\\MyPrivateChildValue' =>
|
|
||||||
array (
|
|
||||||
'prot' =>
|
|
||||||
array (
|
|
||||||
1 => 123,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
'2' =>
|
|
||||||
array (
|
|
||||||
0 =>
|
|
||||||
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::$objects[0],
|
|
||||||
1 =>
|
|
||||||
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::$objects[1],
|
|
||||||
),
|
|
||||||
'3' =>
|
|
||||||
array (
|
|
||||||
),
|
|
||||||
));
|
|
|
@ -4,7 +4,8 @@
|
||||||
'0' => 'Symfony\\Component\\Cache\\Tests\\Marshaller\\MyPrivateValue',
|
'0' => 'Symfony\\Component\\Cache\\Tests\\Marshaller\\MyPrivateValue',
|
||||||
'1' => 'Symfony\\Component\\Cache\\Tests\\Marshaller\\MyPrivateChildValue',
|
'1' => 'Symfony\\Component\\Cache\\Tests\\Marshaller\\MyPrivateChildValue',
|
||||||
)),
|
)),
|
||||||
'1' =>
|
'1' => NULL,
|
||||||
|
'2' =>
|
||||||
array (
|
array (
|
||||||
'Symfony\\Component\\Cache\\Tests\\Marshaller\\MyPrivateValue' =>
|
'Symfony\\Component\\Cache\\Tests\\Marshaller\\MyPrivateValue' =>
|
||||||
array (
|
array (
|
||||||
|
@ -26,18 +27,14 @@
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
'2' =>
|
'3' =>
|
||||||
array (
|
array (
|
||||||
0 =>
|
0 =>
|
||||||
Symfony\Component\Cache\Marshaller\PhpMarshaller\Reference::__set_state(array(
|
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::$objects[0],
|
||||||
'0' => 0,
|
|
||||||
)),
|
|
||||||
1 =>
|
1 =>
|
||||||
Symfony\Component\Cache\Marshaller\PhpMarshaller\Reference::__set_state(array(
|
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::$objects[1],
|
||||||
'0' => 1,
|
|
||||||
)),
|
|
||||||
),
|
),
|
||||||
'3' =>
|
'4' =>
|
||||||
array (
|
array (
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
|
|
|
@ -3,21 +3,18 @@
|
||||||
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::__set_state(array(
|
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::__set_state(array(
|
||||||
'0' => 'C:55:"Symfony\\Component\\Cache\\Tests\\Marshaller\\MySerializable":3:{123}',
|
'0' => 'C:55:"Symfony\\Component\\Cache\\Tests\\Marshaller\\MySerializable":3:{123}',
|
||||||
)),
|
)),
|
||||||
'1' =>
|
'1' => NULL,
|
||||||
array (
|
|
||||||
),
|
|
||||||
'2' =>
|
'2' =>
|
||||||
array (
|
array (
|
||||||
0 =>
|
|
||||||
Symfony\Component\Cache\Marshaller\PhpMarshaller\Reference::__set_state(array(
|
|
||||||
'0' => 0,
|
|
||||||
)),
|
|
||||||
1 =>
|
|
||||||
Symfony\Component\Cache\Marshaller\PhpMarshaller\Reference::__set_state(array(
|
|
||||||
'0' => 0,
|
|
||||||
)),
|
|
||||||
),
|
),
|
||||||
'3' =>
|
'3' =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::$objects[0],
|
||||||
|
1 =>
|
||||||
|
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::$objects[0],
|
||||||
|
),
|
||||||
|
'4' =>
|
||||||
array (
|
array (
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
<?php return Symfony\Component\Cache\Marshaller\PhpMarshaller\Configurator::__set_state(array(
|
|
||||||
'0' =>
|
|
||||||
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::__set_state(array(
|
|
||||||
'0' => 'SplObjectStorage',
|
|
||||||
'1' => 'stdClass',
|
|
||||||
)),
|
|
||||||
'1' =>
|
|
||||||
array (
|
|
||||||
'SplObjectStorage' =>
|
|
||||||
array (
|
|
||||||
'' . "\0" . '' =>
|
|
||||||
array (
|
|
||||||
0 =>
|
|
||||||
array (
|
|
||||||
0 =>
|
|
||||||
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::$objects[1],
|
|
||||||
1 => 345,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
'2' =>
|
|
||||||
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::$objects[0],
|
|
||||||
'3' =>
|
|
||||||
array (
|
|
||||||
),
|
|
||||||
));
|
|
|
@ -4,7 +4,8 @@
|
||||||
'0' => 'SplObjectStorage',
|
'0' => 'SplObjectStorage',
|
||||||
'1' => 'stdClass',
|
'1' => 'stdClass',
|
||||||
)),
|
)),
|
||||||
'1' =>
|
'1' => NULL,
|
||||||
|
'2' =>
|
||||||
array (
|
array (
|
||||||
'SplObjectStorage' =>
|
'SplObjectStorage' =>
|
||||||
array (
|
array (
|
||||||
|
@ -13,19 +14,15 @@
|
||||||
0 =>
|
0 =>
|
||||||
array (
|
array (
|
||||||
0 =>
|
0 =>
|
||||||
Symfony\Component\Cache\Marshaller\PhpMarshaller\Reference::__set_state(array(
|
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::$objects[1],
|
||||||
'0' => 1,
|
|
||||||
)),
|
|
||||||
1 => 345,
|
1 => 345,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
'2' =>
|
|
||||||
Symfony\Component\Cache\Marshaller\PhpMarshaller\Reference::__set_state(array(
|
|
||||||
'0' => 0,
|
|
||||||
)),
|
|
||||||
'3' =>
|
'3' =>
|
||||||
|
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::$objects[0],
|
||||||
|
'4' =>
|
||||||
array (
|
array (
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
<?php return Symfony\Component\Cache\Marshaller\PhpMarshaller\Configurator::__set_state(array(
|
|
||||||
'0' =>
|
|
||||||
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::__set_state(array(
|
|
||||||
'0' => 'Symfony\\Component\\Cache\\Tests\\Marshaller\\MyWakeup',
|
|
||||||
'1' => 'Symfony\\Component\\Cache\\Tests\\Marshaller\\MyWakeup',
|
|
||||||
)),
|
|
||||||
'1' =>
|
|
||||||
array (
|
|
||||||
'Symfony\\Component\\Cache\\Tests\\Marshaller\\MyWakeup' =>
|
|
||||||
array (
|
|
||||||
'sub' =>
|
|
||||||
array (
|
|
||||||
0 =>
|
|
||||||
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::$objects[1],
|
|
||||||
1 => 123,
|
|
||||||
),
|
|
||||||
'baz' =>
|
|
||||||
array (
|
|
||||||
1 => 123,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
'2' =>
|
|
||||||
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::$objects[0],
|
|
||||||
'3' =>
|
|
||||||
array (
|
|
||||||
1 => 1,
|
|
||||||
2 => 0,
|
|
||||||
),
|
|
||||||
));
|
|
|
@ -4,16 +4,15 @@
|
||||||
'0' => 'Symfony\\Component\\Cache\\Tests\\Marshaller\\MyWakeup',
|
'0' => 'Symfony\\Component\\Cache\\Tests\\Marshaller\\MyWakeup',
|
||||||
'1' => 'Symfony\\Component\\Cache\\Tests\\Marshaller\\MyWakeup',
|
'1' => 'Symfony\\Component\\Cache\\Tests\\Marshaller\\MyWakeup',
|
||||||
)),
|
)),
|
||||||
'1' =>
|
'1' => NULL,
|
||||||
|
'2' =>
|
||||||
array (
|
array (
|
||||||
'Symfony\\Component\\Cache\\Tests\\Marshaller\\MyWakeup' =>
|
'Symfony\\Component\\Cache\\Tests\\Marshaller\\MyWakeup' =>
|
||||||
array (
|
array (
|
||||||
'sub' =>
|
'sub' =>
|
||||||
array (
|
array (
|
||||||
0 =>
|
0 =>
|
||||||
Symfony\Component\Cache\Marshaller\PhpMarshaller\Reference::__set_state(array(
|
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::$objects[1],
|
||||||
'0' => 1,
|
|
||||||
)),
|
|
||||||
1 => 123,
|
1 => 123,
|
||||||
),
|
),
|
||||||
'baz' =>
|
'baz' =>
|
||||||
|
@ -22,11 +21,9 @@
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
'2' =>
|
|
||||||
Symfony\Component\Cache\Marshaller\PhpMarshaller\Reference::__set_state(array(
|
|
||||||
'0' => 0,
|
|
||||||
)),
|
|
||||||
'3' =>
|
'3' =>
|
||||||
|
Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry::$objects[0],
|
||||||
|
'4' =>
|
||||||
array (
|
array (
|
||||||
1 => 1,
|
1 => 1,
|
||||||
2 => 0,
|
2 => 0,
|
||||||
|
|
|
@ -13,35 +13,82 @@ namespace Symfony\Component\Cache\Tests\Marshaller;
|
||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use Symfony\Component\Cache\Marshaller\PhpMarshaller;
|
use Symfony\Component\Cache\Marshaller\PhpMarshaller;
|
||||||
|
use Symfony\Component\Cache\Marshaller\PhpMarshaller\Registry;
|
||||||
use Symfony\Component\VarDumper\Test\VarDumperTestTrait;
|
use Symfony\Component\VarDumper\Test\VarDumperTestTrait;
|
||||||
|
|
||||||
class DoctrineProviderTest extends TestCase
|
class DoctrineProviderTest extends TestCase
|
||||||
{
|
{
|
||||||
use VarDumperTestTrait;
|
use VarDumperTestTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \ReflectionException
|
||||||
|
* @expectedExceptionMessage Class SomeNotExistingClass does not exist
|
||||||
|
*/
|
||||||
|
public function testPhpIncompleteClassesAreForbidden()
|
||||||
|
{
|
||||||
|
$unserializeCallback = ini_set('unserialize_callback_func', 'var_dump');
|
||||||
|
try {
|
||||||
|
Registry::__set_state(array('O:20:"SomeNotExistingClass":0:{}'));
|
||||||
|
} finally {
|
||||||
|
$this->assertSame('var_dump', ini_set('unserialize_callback_func', $unserializeCallback));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider provideFailingSerialization
|
||||||
|
* @expectedException \Exception
|
||||||
|
* @expectedExceptionMessageRegexp Serialization of '.*' is not allowed
|
||||||
|
*/
|
||||||
|
public function testFailingSerialization($value)
|
||||||
|
{
|
||||||
|
$expectedDump = $this->getDump($value);
|
||||||
|
try {
|
||||||
|
PhpMarshaller::marshall($value);
|
||||||
|
} finally {
|
||||||
|
$this->assertDumpEquals(rtrim($expectedDump), $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function provideFailingSerialization()
|
||||||
|
{
|
||||||
|
yield array(hash_init('md5'));
|
||||||
|
yield array(new \ReflectionClass('stdClass'));
|
||||||
|
yield array((new \ReflectionFunction(function (): int {}))->getReturnType());
|
||||||
|
yield array(new \ReflectionGenerator((function () { yield 123; })()));
|
||||||
|
yield array(function () {});
|
||||||
|
yield array(function () { yield 123; });
|
||||||
|
yield array(new \SplFileInfo(__FILE__));
|
||||||
|
yield array($h = fopen(__FILE__, 'r'));
|
||||||
|
yield array(array($h));
|
||||||
|
|
||||||
|
$a = array(null, $h);
|
||||||
|
$a[0] = &$a;
|
||||||
|
|
||||||
|
yield array($a);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dataProvider provideMarshall
|
* @dataProvider provideMarshall
|
||||||
*/
|
*/
|
||||||
public function testMarshall(string $testName, $value, int $expectedObjectsCount)
|
public function testMarshall(string $testName, $value, bool $staticValueExpected = false)
|
||||||
{
|
{
|
||||||
$objectsCount = 0;
|
$serializedValue = serialize($value);
|
||||||
$marshalledValue = PhpMarshaller::marshall($value, $objectsCount);
|
$isStaticValue = true;
|
||||||
|
$marshalledValue = PhpMarshaller::marshall($value, $isStaticValue);
|
||||||
|
|
||||||
$this->assertSame($expectedObjectsCount, $objectsCount);
|
$this->assertSame($staticValueExpected, $isStaticValue);
|
||||||
|
$this->assertSame($serializedValue, serialize($value));
|
||||||
|
|
||||||
$dump = '<?php return '.var_export($marshalledValue, true).";\n";
|
$dump = '<?php return '.$marshalledValue.";\n";
|
||||||
$fixtureFile = __DIR__.'/Fixtures/'.$testName.'.php';
|
$fixtureFile = __DIR__.'/Fixtures/'.$testName.'.php';
|
||||||
$this->assertStringEqualsFile($fixtureFile, $dump);
|
$this->assertStringEqualsFile($fixtureFile, $dump);
|
||||||
|
|
||||||
if ($objectsCount) {
|
if ('incomplete-class' === $testName) {
|
||||||
$marshalledValue = include $fixtureFile;
|
return;
|
||||||
$this->assertDumpEquals($value, $marshalledValue);
|
}
|
||||||
|
$marshalledValue = include $fixtureFile;
|
||||||
|
|
||||||
$dump = PhpMarshaller::optimize($dump);
|
if (!$isStaticValue) {
|
||||||
$fixtureFile = __DIR__.'/Fixtures/'.$testName.'.optimized.php';
|
|
||||||
$this->assertStringEqualsFile($fixtureFile, $dump);
|
|
||||||
|
|
||||||
$marshalledValue = include $fixtureFile;
|
|
||||||
$this->assertDumpEquals($value, $marshalledValue);
|
$this->assertDumpEquals($value, $marshalledValue);
|
||||||
} else {
|
} else {
|
||||||
$this->assertSame($value, $marshalledValue);
|
$this->assertSame($value, $marshalledValue);
|
||||||
|
@ -50,23 +97,23 @@ class DoctrineProviderTest extends TestCase
|
||||||
|
|
||||||
public function provideMarshall()
|
public function provideMarshall()
|
||||||
{
|
{
|
||||||
yield array('bool', true, 0);
|
yield array('bool', true, true);
|
||||||
yield array('simple-array', array(123, array('abc')), 0);
|
yield array('simple-array', array(123, array('abc')), true);
|
||||||
yield array('datetime', \DateTime::createFromFormat('U', 0), 1);
|
yield array('datetime', \DateTime::createFromFormat('U', 0));
|
||||||
|
|
||||||
$value = new \ArrayObject();
|
$value = new \ArrayObject();
|
||||||
$value[0] = 1;
|
$value[0] = 1;
|
||||||
$value->foo = new \ArrayObject();
|
$value->foo = new \ArrayObject();
|
||||||
$value[1] = $value;
|
$value[1] = $value;
|
||||||
|
|
||||||
yield array('array-object', $value, 3);
|
yield array('array-object', $value);
|
||||||
|
|
||||||
yield array('array-iterator', new \ArrayIterator(array(123), 1), 1);
|
yield array('array-iterator', new \ArrayIterator(array(123), 1));
|
||||||
yield array('array-object-custom', new MyArrayObject(array(234)), 1);
|
yield array('array-object-custom', new MyArrayObject(array(234)));
|
||||||
|
|
||||||
$value = new MySerializable();
|
$value = new MySerializable();
|
||||||
|
|
||||||
yield array('serializable', array($value, $value), 2);
|
yield array('serializable', array($value, $value));
|
||||||
|
|
||||||
$value = new MyWakeup();
|
$value = new MyWakeup();
|
||||||
$value->sub = new MyWakeup();
|
$value->sub = new MyWakeup();
|
||||||
|
@ -74,16 +121,29 @@ class DoctrineProviderTest extends TestCase
|
||||||
$value->sub->bis = 123;
|
$value->sub->bis = 123;
|
||||||
$value->sub->baz = 123;
|
$value->sub->baz = 123;
|
||||||
|
|
||||||
yield array('wakeup', $value, 2);
|
yield array('wakeup', $value);
|
||||||
|
|
||||||
yield array('clone', array(new MyCloneable(), new MyNotCloneable()), 2);
|
yield array('clone', array(new MyCloneable(), new MyNotCloneable()));
|
||||||
|
|
||||||
yield array('private', array(new MyPrivateValue(123, 234), new MyPrivateChildValue(123, 234)), 2);
|
yield array('private', array(new MyPrivateValue(123, 234), new MyPrivateChildValue(123, 234)));
|
||||||
|
|
||||||
$value = new \SplObjectStorage();
|
$value = new \SplObjectStorage();
|
||||||
$value[new \stdClass()] = 345;
|
$value[new \stdClass()] = 345;
|
||||||
|
|
||||||
yield array('spl-object-storage', $value, 2);
|
yield array('spl-object-storage', $value);
|
||||||
|
|
||||||
|
yield array('incomplete-class', unserialize('O:20:"SomeNotExistingClass":0:{}'));
|
||||||
|
|
||||||
|
$value = array((object) array());
|
||||||
|
$value[1] = &$value[0];
|
||||||
|
$value[2] = $value[0];
|
||||||
|
|
||||||
|
yield array('hard-references', $value);
|
||||||
|
|
||||||
|
$value = array();
|
||||||
|
$value[0] = &$value;
|
||||||
|
|
||||||
|
yield array('hard-references-recursive', $value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -70,33 +70,29 @@ EOF;
|
||||||
|
|
||||||
foreach ($values as $key => $value) {
|
foreach ($values as $key => $value) {
|
||||||
CacheItem::validateKey(\is_int($key) ? (string) $key : $key);
|
CacheItem::validateKey(\is_int($key) ? (string) $key : $key);
|
||||||
$objectsCount = 0;
|
$isStaticValue = true;
|
||||||
|
|
||||||
if (null === $value) {
|
if (null === $value) {
|
||||||
$value = 'N;';
|
$value = "'N;'";
|
||||||
} elseif (\is_object($value) || \is_array($value)) {
|
} elseif (\is_object($value) || \is_array($value)) {
|
||||||
try {
|
try {
|
||||||
$e = null;
|
$value = PhpMarshaller::marshall($value, $isStaticValue);
|
||||||
$serialized = serialize($value);
|
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
}
|
|
||||||
if (null !== $e || false === $serialized) {
|
|
||||||
throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable %s value.', $key, \is_object($value) ? \get_class($value) : 'array'), 0, $e);
|
throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable %s value.', $key, \is_object($value) ? \get_class($value) : 'array'), 0, $e);
|
||||||
}
|
}
|
||||||
// Keep value serialized if it contains any internal references
|
|
||||||
$value = false !== strpos($serialized, ';R:') ? $serialized : PhpMarshaller::marshall($value, $objectsCount);
|
|
||||||
} elseif (\is_string($value)) {
|
} elseif (\is_string($value)) {
|
||||||
// Wrap strings if they could be confused with serialized objects or arrays
|
// Wrap "N;" in a closure to not confuse it with an encoded `null`
|
||||||
if ('N;' === $value || (isset($value[2]) && ':' === $value[1])) {
|
if ('N;' === $value) {
|
||||||
++$objectsCount;
|
$isStaticValue = false;
|
||||||
}
|
}
|
||||||
|
$value = var_export($value, true);
|
||||||
} elseif (!\is_scalar($value)) {
|
} elseif (!\is_scalar($value)) {
|
||||||
throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable %s value.', $key, \gettype($value)));
|
throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable %s value.', $key, \gettype($value)));
|
||||||
|
} else {
|
||||||
|
$value = var_export($value, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
$value = var_export($value, true);
|
if (!$isStaticValue) {
|
||||||
if ($objectsCount) {
|
|
||||||
$value = PhpMarshaller::optimize($value);
|
|
||||||
$value = "static function () {\nreturn {$value};\n}";
|
$value = "static function () {\nreturn {$value};\n}";
|
||||||
}
|
}
|
||||||
$hash = hash('md5', $value);
|
$hash = hash('md5', $value);
|
||||||
|
|
|
@ -13,7 +13,6 @@ namespace Symfony\Component\Cache\Traits;
|
||||||
|
|
||||||
use Symfony\Component\Cache\Exception\CacheException;
|
use Symfony\Component\Cache\Exception\CacheException;
|
||||||
use Symfony\Component\Cache\Exception\InvalidArgumentException;
|
use Symfony\Component\Cache\Exception\InvalidArgumentException;
|
||||||
use Symfony\Component\Cache\Marshaller\DefaultMarshaller;
|
|
||||||
use Symfony\Component\Cache\Marshaller\PhpMarshaller;
|
use Symfony\Component\Cache\Marshaller\PhpMarshaller;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -30,7 +29,6 @@ trait PhpFilesTrait
|
||||||
doDelete as private doCommonDelete;
|
doDelete as private doCommonDelete;
|
||||||
}
|
}
|
||||||
|
|
||||||
private $marshaller;
|
|
||||||
private $includeHandler;
|
private $includeHandler;
|
||||||
private $appendOnly;
|
private $appendOnly;
|
||||||
private $values = array();
|
private $values = array();
|
||||||
|
@ -92,8 +90,6 @@ trait PhpFilesTrait
|
||||||
$values[$id] = null;
|
$values[$id] = null;
|
||||||
} elseif ($value instanceof \Closure) {
|
} elseif ($value instanceof \Closure) {
|
||||||
$values[$id] = $value();
|
$values[$id] = $value();
|
||||||
} elseif (\is_string($value) && isset($value[2]) && ':' === $value[1]) {
|
|
||||||
$values[$id] = ($this->marshaller ?? $this->marshaller = new DefaultMarshaller())->unmarshall($value);
|
|
||||||
} else {
|
} else {
|
||||||
$values[$id] = $value;
|
$values[$id] = $value;
|
||||||
}
|
}
|
||||||
|
@ -165,32 +161,28 @@ trait PhpFilesTrait
|
||||||
|
|
||||||
foreach ($values as $key => $value) {
|
foreach ($values as $key => $value) {
|
||||||
unset($this->values[$key]);
|
unset($this->values[$key]);
|
||||||
$objectsCount = 0;
|
$isStaticValue = true;
|
||||||
if (null === $value) {
|
if (null === $value) {
|
||||||
$value = 'N;';
|
$value = "'N;'";
|
||||||
} elseif (\is_object($value) || \is_array($value)) {
|
} elseif (\is_object($value) || \is_array($value)) {
|
||||||
try {
|
try {
|
||||||
$e = null;
|
$value = PhpMarshaller::marshall($value, $isStaticValue);
|
||||||
$serialized = serialize($value);
|
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
}
|
|
||||||
if (null !== $e || false === $serialized) {
|
|
||||||
throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable %s value.', $key, \is_object($value) ? \get_class($value) : 'array'), 0, $e);
|
throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable %s value.', $key, \is_object($value) ? \get_class($value) : 'array'), 0, $e);
|
||||||
}
|
}
|
||||||
// Keep value serialized if it contains any internal references
|
|
||||||
$value = false !== strpos($serialized, ';R:') ? $serialized : PhpMarshaller::marshall($value, $objectsCount);
|
|
||||||
} elseif (\is_string($value)) {
|
} elseif (\is_string($value)) {
|
||||||
// Wrap strings if they could be confused with serialized objects or arrays
|
// Wrap "N;" in a closure to not confuse it with an encoded `null`
|
||||||
if ('N;' === $value || (isset($value[2]) && ':' === $value[1])) {
|
if ('N;' === $value) {
|
||||||
++$objectsCount;
|
$isStaticValue = false;
|
||||||
}
|
}
|
||||||
|
$value = var_export($value, true);
|
||||||
} elseif (!\is_scalar($value)) {
|
} elseif (!\is_scalar($value)) {
|
||||||
throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable %s value.', $key, \gettype($value)));
|
throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable %s value.', $key, \gettype($value)));
|
||||||
|
} else {
|
||||||
|
$value = var_export($value, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
$value = var_export($value, true);
|
if (!$isStaticValue) {
|
||||||
if ($objectsCount) {
|
|
||||||
$value = PhpMarshaller::optimize($value);
|
|
||||||
$value = "static function () {\n\nreturn {$value};\n\n}";
|
$value = "static function () {\n\nreturn {$value};\n\n}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Reference in New Issue