[VarExporter] optimize dumped code in time and space
This commit is contained in:
parent
428c25f73b
commit
07e90d71d8
@ -48,10 +48,11 @@ class Exporter
|
||||
$refs[$k] = $value = $values[$k];
|
||||
if ($value instanceof Reference && 0 > $value->id) {
|
||||
$valuesAreStatic = false;
|
||||
++$value->count;
|
||||
continue;
|
||||
}
|
||||
$refsPool[] = array(&$refs[$k], $value, &$value);
|
||||
$refs[$k] = $values[$k] = new Reference(-\count($refsPool));
|
||||
$refs[$k] = $values[$k] = new Reference(-\count($refsPool), $value);
|
||||
}
|
||||
|
||||
if (\is_array($value)) {
|
||||
@ -80,12 +81,13 @@ class Exporter
|
||||
Registry::getClassReflector($class);
|
||||
serialize(Registry::$prototypes[$class]);
|
||||
}
|
||||
$reflector = Registry::$reflectors[$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();
|
||||
$proto = Registry::$cloneable[$class] ? clone Registry::$prototypes[$class] : $reflector->newInstanceWithoutConstructor();
|
||||
$properties = self::getArrayObjectProperties($value, $arrayValue, $proto);
|
||||
} elseif ($value instanceof \SplObjectStorage) {
|
||||
// By implementing Serializable, SplObjectStorage breaks internal references,
|
||||
@ -116,20 +118,29 @@ class Exporter
|
||||
foreach ($arrayValue as $name => $v) {
|
||||
$n = (string) $name;
|
||||
if ('' === $n || "\0" !== $n[0]) {
|
||||
$c = $class;
|
||||
$c = '*';
|
||||
$properties[$c][$n] = $v;
|
||||
unset($sleep[$n]);
|
||||
} elseif ('*' === $n[1]) {
|
||||
$c = $class;
|
||||
$n = substr($n, 3);
|
||||
$c = $reflector->getProperty($n)->class;
|
||||
if ('Error' === $c) {
|
||||
$c = 'TypeError';
|
||||
} elseif ('Exception' === $c) {
|
||||
$c = 'ErrorException';
|
||||
}
|
||||
$properties[$c][$n] = $v;
|
||||
unset($sleep[$n]);
|
||||
} 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 (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]);
|
||||
@ -173,11 +184,14 @@ class Exporter
|
||||
|
||||
if ($value instanceof Reference) {
|
||||
if (0 <= $value->id) {
|
||||
return '\\'.Registry::class.'::$objects['.$value->id.']';
|
||||
return '$o['.$value->id.']';
|
||||
}
|
||||
if (!$value->count) {
|
||||
return self::export($value->value, $indent);
|
||||
}
|
||||
$value = -$value->id;
|
||||
|
||||
return '&\\'.Registry::class.'::$references['.$value.']';
|
||||
return '&$r['.$value.']';
|
||||
}
|
||||
$subIndent = $indent.' ';
|
||||
|
||||
@ -213,9 +227,11 @@ class Exporter
|
||||
$code = '';
|
||||
foreach ($value as $k => $v) {
|
||||
$code .= $subIndent;
|
||||
if ($k !== ++$j) {
|
||||
if (!\is_int($k) || 1 !== $k - $j) {
|
||||
$code .= self::export($k, $subIndent).' => ';
|
||||
$j = INF;
|
||||
}
|
||||
if (\is_int($k)) {
|
||||
$j = $k;
|
||||
}
|
||||
$code .= self::export($v, $subIndent).",\n";
|
||||
}
|
||||
@ -224,82 +240,110 @@ class Exporter
|
||||
}
|
||||
|
||||
if ($value instanceof Values) {
|
||||
$code = '';
|
||||
$code = $subIndent."\$r = [],\n";
|
||||
foreach ($value->values as $k => $v) {
|
||||
$code .= $subIndent.'\\'.Registry::class.'::$references['.$k.'] = '.self::export($v, $subIndent).",\n";
|
||||
$code .= $subIndent.'$r['.$k.'] = '.self::export($v, $subIndent).",\n";
|
||||
}
|
||||
|
||||
return "[\n".$code.$indent.']';
|
||||
}
|
||||
|
||||
if ($value instanceof Registry) {
|
||||
$code = '';
|
||||
$reflectors = array();
|
||||
$serializables = array();
|
||||
|
||||
foreach ($value as $k => $class) {
|
||||
if (':' === ($class[1] ?? null)) {
|
||||
$serializables[$k] = $class;
|
||||
continue;
|
||||
}
|
||||
$c = '\\'.$class.'::class';
|
||||
$reflectors[$class] = '\\'.Registry::class.'::$reflectors['.$c.'] ?? \\'.Registry::class.'::getClassReflector('.$c.', '
|
||||
.self::export(Registry::$instantiableWithoutConstructor[$class]).', '
|
||||
.self::export(Registry::$cloneable[$class])
|
||||
.')';
|
||||
|
||||
if (Registry::$cloneable[$class]) {
|
||||
$code .= $subIndent.'clone \\'.Registry::class.'::$prototypes['.$c."],\n";
|
||||
} elseif (Registry::$instantiableWithoutConstructor[$class]) {
|
||||
$code .= $subIndent.'\\'.Registry::class.'::$reflectors['.$c."]->newInstanceWithoutConstructor(),\n";
|
||||
} else {
|
||||
$code .= $subIndent.'\\'.Registry::class.'::$reflectors['.$c."]->newInstance(),\n";
|
||||
}
|
||||
}
|
||||
|
||||
if ($reflectors) {
|
||||
$code = "[\n".$subIndent.implode(",\n".$subIndent, $reflectors).",\n".$indent."], [\n".$code.$indent.'], ';
|
||||
$code .= !$serializables ? "[\n".$indent.']' : self::export($serializables, $indent);
|
||||
} else {
|
||||
$code = '[], []';
|
||||
$code .= ', '.self::export($serializables, $indent);
|
||||
}
|
||||
|
||||
return '\\'.Registry::class.'::push('.$code.')';
|
||||
return self::exportRegistry($value, $indent, $subIndent);
|
||||
}
|
||||
|
||||
if ($value instanceof Configurator) {
|
||||
$code = '';
|
||||
foreach ($value->properties as $class => $properties) {
|
||||
$code .= $subIndent.' \\'.$class.'::class => '.self::export($properties, $subIndent.' ').",\n";
|
||||
}
|
||||
|
||||
$code = array(
|
||||
self::export($value->registry, $subIndent),
|
||||
self::export($value->values, $subIndent),
|
||||
'' !== $code ? "[\n".$code.$subIndent.']' : '[]',
|
||||
self::export($value->value, $subIndent),
|
||||
self::export($value->wakeups, $subIndent),
|
||||
);
|
||||
|
||||
return '\\'.\get_class($value)."::pop(\n".$subIndent.implode(",\n".$subIndent, $code)."\n".$indent.')';
|
||||
if ($value instanceof Hydrator) {
|
||||
return self::exportHydrator($value, $indent, $subIndent);
|
||||
}
|
||||
|
||||
throw new \UnexpectedValueException(sprintf('Cannot export value of type "%s".', \is_object($value) ? \get_class($value) : \gettype($value)));
|
||||
}
|
||||
|
||||
private static function exportRegistry(Registry $value, string $indent, string $subIndent): string
|
||||
{
|
||||
$code = '';
|
||||
$reflectors = array();
|
||||
$serializables = array();
|
||||
$seen = array();
|
||||
$prototypesAccess = 0;
|
||||
$factoriesAccess = 0;
|
||||
$r = '\\'.Registry::class;
|
||||
$j = -1;
|
||||
|
||||
foreach ($value as $k => $class) {
|
||||
if (':' === ($class[1] ?? null)) {
|
||||
$serializables[$k] = $class;
|
||||
continue;
|
||||
}
|
||||
$code .= $subIndent.(1 !== $k - $j ? $k.' => ' : '');
|
||||
$j = $k;
|
||||
$eol = ",\n";
|
||||
$c = '[\\'.$class.'::class]';
|
||||
|
||||
if ($seen[$class] ?? false) {
|
||||
if (Registry::$cloneable[$class]) {
|
||||
++$prototypesAccess;
|
||||
$code .= 'clone $p'.$c;
|
||||
} else {
|
||||
++$factoriesAccess;
|
||||
$code .= '$f'.$c.'()';
|
||||
}
|
||||
} else {
|
||||
$seen[$class] = true;
|
||||
if (Registry::$cloneable[$class]) {
|
||||
$code .= 'clone ('.($prototypesAccess++ ? '$p' : '($p =& '.$r.'::$prototypes)').$c.' ?? '.$r.'::p';
|
||||
} else {
|
||||
$code .= '('.($factoriesAccess++ ? '$f' : '($f =& '.$r.'::$factories)').$c.' ?? '.$r.'::f';
|
||||
$eol = '()'.$eol;
|
||||
}
|
||||
$code .= '('.substr($c, 1, -1).', '.self::export(Registry::$instantiableWithoutConstructor[$class]).'))';
|
||||
}
|
||||
$code .= $eol;
|
||||
}
|
||||
|
||||
if (1 === $prototypesAccess) {
|
||||
$code = str_replace('($p =& '.$r.'::$prototypes)', $r.'::$prototypes', $code);
|
||||
}
|
||||
if (1 === $factoriesAccess) {
|
||||
$code = str_replace('($f =& '.$r.'::$factories)', $r.'::$factories', $code);
|
||||
}
|
||||
if ('' !== $code) {
|
||||
$code = "\n".$code.$indent;
|
||||
}
|
||||
|
||||
if ($serializables) {
|
||||
$code = $r.'::unserialize(['.$code.'], '.self::export($serializables, $indent).')';
|
||||
} else {
|
||||
$code = '['.$code.']';
|
||||
}
|
||||
|
||||
return '$o = '.$code;
|
||||
}
|
||||
|
||||
private static function exportHydrator(Hydrator $value, string $indent, string $subIndent): string
|
||||
{
|
||||
$code = '';
|
||||
foreach ($value->properties as $class => $properties) {
|
||||
$c = '*' !== $class ? '\\'.$class.'::class' : "'*'";
|
||||
$code .= $subIndent.' '.$c.' => '.self::export($properties, $subIndent.' ').",\n";
|
||||
}
|
||||
|
||||
$code = array(
|
||||
self::export($value->registry, $subIndent),
|
||||
self::export($value->values, $subIndent),
|
||||
'' !== $code ? "[\n".$code.$subIndent.']' : '[]',
|
||||
self::export($value->value, $subIndent),
|
||||
self::export($value->wakeups, $subIndent),
|
||||
);
|
||||
|
||||
return '\\'.\get_class($value)."::hydrate(\n".$subIndent.implode(",\n".$subIndent, $code)."\n".$indent.')';
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @param \ArrayIterator|\ArrayObject $proto
|
||||
*/
|
||||
public static function getArrayObjectProperties($value, &$arrayValue, $proto)
|
||||
private static function getArrayObjectProperties($value, array &$arrayValue, $proto): array
|
||||
{
|
||||
$reflector = $value instanceof \ArrayIterator ? 'ArrayIterator' : 'ArrayObject';
|
||||
$reflector = Registry::$reflectors[$reflector] ?? Registry::getClassReflector($reflector);
|
||||
|
@ -16,9 +16,9 @@ namespace Symfony\Component\VarExporter\Internal;
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class Configurator
|
||||
class Hydrator
|
||||
{
|
||||
public static $configurators = array();
|
||||
public static $hydrators = array();
|
||||
|
||||
public $registry;
|
||||
public $values;
|
||||
@ -35,12 +35,10 @@ class Configurator
|
||||
$this->wakeups = $wakeups;
|
||||
}
|
||||
|
||||
public static function pop($objects, $values, $properties, $value, $wakeups)
|
||||
public static function hydrate($objects, $values, $properties, $value, $wakeups)
|
||||
{
|
||||
list(Registry::$objects, Registry::$references) = \array_pop(Registry::$stack);
|
||||
|
||||
foreach ($properties as $class => $vars) {
|
||||
(self::$configurators[$class] ?? self::getConfigurator($class))($vars, $objects);
|
||||
(self::$hydrators[$class] ?? self::getHydrator($class))($vars, $objects);
|
||||
}
|
||||
foreach ($wakeups as $i) {
|
||||
$objects[$i]->__wakeup();
|
||||
@ -49,18 +47,22 @@ class Configurator
|
||||
return $value;
|
||||
}
|
||||
|
||||
public static function getConfigurator($class)
|
||||
public static function getHydrator($class)
|
||||
{
|
||||
$classReflector = Registry::$reflectors[$class] ?? Registry::getClassReflector($class);
|
||||
|
||||
if (!$classReflector->isInternal()) {
|
||||
return self::$configurators[$class] = \Closure::bind(function ($properties, $objects) {
|
||||
if ('*' === $class) {
|
||||
return self::$hydrators[$class] = static function ($properties, $objects) {
|
||||
foreach ($properties as $name => $values) {
|
||||
foreach ($values as $i => $v) {
|
||||
$objects[$i]->$name = $v;
|
||||
}
|
||||
}
|
||||
}, null, $class);
|
||||
};
|
||||
}
|
||||
|
||||
$classReflector = Registry::$reflectors[$class] ?? Registry::getClassReflector($class);
|
||||
|
||||
if (!$classReflector->isInternal()) {
|
||||
return self::$hydrators[$class] = (self::$hydrators['*'] ?? self::getHydrator('*'))->bindTo(null, $class);
|
||||
}
|
||||
|
||||
switch ($class) {
|
||||
@ -68,7 +70,7 @@ class Configurator
|
||||
case 'ArrayObject':
|
||||
$constructor = $classReflector->getConstructor();
|
||||
|
||||
return self::$configurators[$class] = static function ($properties, $objects) use ($constructor) {
|
||||
return self::$hydrators[$class] = static function ($properties, $objects) use ($constructor) {
|
||||
foreach ($properties as $name => $values) {
|
||||
if ("\0" !== $name) {
|
||||
foreach ($values as $i => $v) {
|
||||
@ -81,8 +83,16 @@ class Configurator
|
||||
}
|
||||
};
|
||||
|
||||
case 'ErrorException':
|
||||
return self::$hydrators[$class] = (self::$hydrators['*'] ?? self::getHydrator('*'))->bindTo(null, new class() extends \ErrorException {
|
||||
});
|
||||
|
||||
case 'TypeError':
|
||||
return self::$hydrators[$class] = (self::$hydrators['*'] ?? self::getHydrator('*'))->bindTo(null, new class() extends \Error {
|
||||
});
|
||||
|
||||
case 'SplObjectStorage':
|
||||
return self::$configurators[$class] = static function ($properties, $objects) {
|
||||
return self::$hydrators[$class] = static function ($properties, $objects) {
|
||||
foreach ($properties as $name => $values) {
|
||||
if ("\0" === $name) {
|
||||
foreach ($values as $i => $v) {
|
||||
@ -100,23 +110,18 @@ class Configurator
|
||||
}
|
||||
|
||||
$propertyReflectors = array();
|
||||
foreach ($classReflector->getProperties(\ReflectionProperty::IS_PROTECTED | \ReflectionProperty::IS_PRIVATE) as $propertyReflector) {
|
||||
foreach ($classReflector->getProperties() as $propertyReflector) {
|
||||
if (!$propertyReflector->isStatic()) {
|
||||
$propertyReflector->setAccessible(true);
|
||||
$propertyReflectors[$propertyReflector->name] = $propertyReflector;
|
||||
}
|
||||
}
|
||||
|
||||
return self::$configurators[$class] = static function ($properties, $objects) use ($propertyReflectors) {
|
||||
return self::$hydrators[$class] = static function ($properties, $objects) use ($propertyReflectors) {
|
||||
foreach ($properties as $name => $values) {
|
||||
if (isset($propertyReflectors[$name])) {
|
||||
foreach ($values as $i => $v) {
|
||||
$propertyReflectors[$name]->setValue($objects[$i], $v);
|
||||
}
|
||||
} else {
|
||||
foreach ($values as $i => $v) {
|
||||
$objects[$i]->$name = $v;
|
||||
}
|
||||
$p = $propertyReflectors[$name];
|
||||
foreach ($values as $i => $v) {
|
||||
$p->setValue($objects[$i], $v);
|
||||
}
|
||||
}
|
||||
};
|
@ -19,9 +19,12 @@ namespace Symfony\Component\VarExporter\Internal;
|
||||
class Reference
|
||||
{
|
||||
public $id;
|
||||
public $value;
|
||||
public $count = 0;
|
||||
|
||||
public function __construct(int $id)
|
||||
public function __construct(int $id, $value = null)
|
||||
{
|
||||
$this->id = $id;
|
||||
$this->value = $value;
|
||||
}
|
||||
}
|
||||
|
@ -18,11 +18,9 @@ namespace Symfony\Component\VarExporter\Internal;
|
||||
*/
|
||||
class Registry
|
||||
{
|
||||
public static $stack = array();
|
||||
public static $objects = array();
|
||||
public static $references = array();
|
||||
public static $reflectors = array();
|
||||
public static $prototypes = array();
|
||||
public static $factories = array();
|
||||
public static $cloneable = array();
|
||||
public static $instantiableWithoutConstructor = array();
|
||||
|
||||
@ -33,28 +31,33 @@ class Registry
|
||||
}
|
||||
}
|
||||
|
||||
public static function push($reflectors, $objects, $serializables)
|
||||
public static function unserialize($objects, $serializables)
|
||||
{
|
||||
self::$stack[] = array(self::$objects, self::$references);
|
||||
self::$references = array();
|
||||
|
||||
if (!$serializables) {
|
||||
return self::$objects = $objects;
|
||||
}
|
||||
$unserializeCallback = ini_set('unserialize_callback_func', __CLASS__.'::getClassReflector');
|
||||
|
||||
try {
|
||||
foreach ($serializables as $k => $v) {
|
||||
$objects[$k] = unserialize($v);
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
list(self::$objects, self::$references) = array_pop(self::$stack);
|
||||
throw $e;
|
||||
} finally {
|
||||
ini_set('unserialize_callback_func', $unserializeCallback);
|
||||
}
|
||||
|
||||
return self::$objects = $objects;
|
||||
return $objects;
|
||||
}
|
||||
|
||||
public static function p($class, $instantiableWithoutConstructor)
|
||||
{
|
||||
self::getClassReflector($class, $instantiableWithoutConstructor, true);
|
||||
|
||||
return self::$prototypes[$class];
|
||||
}
|
||||
|
||||
public static function f($class, $instantiableWithoutConstructor)
|
||||
{
|
||||
$reflector = self::$reflectors[$class] ?? self::getClassReflector($class, $instantiableWithoutConstructor, false);
|
||||
|
||||
return self::$factories[$class] = \Closure::fromCallable(array($reflector, $instantiableWithoutConstructor ? 'newInstanceWithoutConstructor' : 'newInstance'));
|
||||
}
|
||||
|
||||
public static function getClassReflector($class, $instantiableWithoutConstructor = null, $cloneable = null)
|
||||
|
@ -1,12 +1,9 @@
|
||||
<?php
|
||||
|
||||
return \Symfony\Component\VarExporter\Internal\Configurator::pop(
|
||||
\Symfony\Component\VarExporter\Internal\Registry::push([
|
||||
\Symfony\Component\VarExporter\Internal\Registry::$reflectors[\ArrayIterator::class] ?? \Symfony\Component\VarExporter\Internal\Registry::getClassReflector(\ArrayIterator::class, true, true),
|
||||
], [
|
||||
clone \Symfony\Component\VarExporter\Internal\Registry::$prototypes[\ArrayIterator::class],
|
||||
], [
|
||||
]),
|
||||
return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate(
|
||||
$o = [
|
||||
clone (\Symfony\Component\VarExporter\Internal\Registry::$prototypes[\ArrayIterator::class] ?? \Symfony\Component\VarExporter\Internal\Registry::p(\ArrayIterator::class, true)),
|
||||
],
|
||||
null,
|
||||
[
|
||||
\ArrayIterator::class => [
|
||||
@ -20,6 +17,6 @@ return \Symfony\Component\VarExporter\Internal\Configurator::pop(
|
||||
],
|
||||
],
|
||||
],
|
||||
\Symfony\Component\VarExporter\Internal\Registry::$objects[0],
|
||||
$o[0],
|
||||
[]
|
||||
);
|
||||
|
@ -1,12 +1,9 @@
|
||||
<?php
|
||||
|
||||
return \Symfony\Component\VarExporter\Internal\Configurator::pop(
|
||||
\Symfony\Component\VarExporter\Internal\Registry::push([
|
||||
\Symfony\Component\VarExporter\Internal\Registry::$reflectors[\Symfony\Component\VarExporter\Tests\MyArrayObject::class] ?? \Symfony\Component\VarExporter\Internal\Registry::getClassReflector(\Symfony\Component\VarExporter\Tests\MyArrayObject::class, true, true),
|
||||
], [
|
||||
clone \Symfony\Component\VarExporter\Internal\Registry::$prototypes[\Symfony\Component\VarExporter\Tests\MyArrayObject::class],
|
||||
], [
|
||||
]),
|
||||
return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate(
|
||||
$o = [
|
||||
clone (\Symfony\Component\VarExporter\Internal\Registry::$prototypes[\Symfony\Component\VarExporter\Tests\MyArrayObject::class] ?? \Symfony\Component\VarExporter\Internal\Registry::p(\Symfony\Component\VarExporter\Tests\MyArrayObject::class, true)),
|
||||
],
|
||||
null,
|
||||
[
|
||||
\ArrayObject::class => [
|
||||
@ -20,6 +17,6 @@ return \Symfony\Component\VarExporter\Internal\Configurator::pop(
|
||||
],
|
||||
],
|
||||
],
|
||||
\Symfony\Component\VarExporter\Internal\Registry::$objects[0],
|
||||
$o[0],
|
||||
[]
|
||||
);
|
||||
|
@ -1,13 +1,10 @@
|
||||
<?php
|
||||
|
||||
return \Symfony\Component\VarExporter\Internal\Configurator::pop(
|
||||
\Symfony\Component\VarExporter\Internal\Registry::push([
|
||||
\Symfony\Component\VarExporter\Internal\Registry::$reflectors[\ArrayObject::class] ?? \Symfony\Component\VarExporter\Internal\Registry::getClassReflector(\ArrayObject::class, true, true),
|
||||
], [
|
||||
clone \Symfony\Component\VarExporter\Internal\Registry::$prototypes[\ArrayObject::class],
|
||||
clone \Symfony\Component\VarExporter\Internal\Registry::$prototypes[\ArrayObject::class],
|
||||
], [
|
||||
]),
|
||||
return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate(
|
||||
$o = [
|
||||
clone (($p =& \Symfony\Component\VarExporter\Internal\Registry::$prototypes)[\ArrayObject::class] ?? \Symfony\Component\VarExporter\Internal\Registry::p(\ArrayObject::class, true)),
|
||||
clone $p[\ArrayObject::class],
|
||||
],
|
||||
null,
|
||||
[
|
||||
\ArrayObject::class => [
|
||||
@ -15,16 +12,18 @@ return \Symfony\Component\VarExporter\Internal\Configurator::pop(
|
||||
[
|
||||
[
|
||||
1,
|
||||
\Symfony\Component\VarExporter\Internal\Registry::$objects[0],
|
||||
$o[0],
|
||||
],
|
||||
0,
|
||||
],
|
||||
],
|
||||
],
|
||||
'*' => [
|
||||
'foo' => [
|
||||
\Symfony\Component\VarExporter\Internal\Registry::$objects[1],
|
||||
$o[1],
|
||||
],
|
||||
],
|
||||
],
|
||||
\Symfony\Component\VarExporter\Internal\Registry::$objects[0],
|
||||
$o[0],
|
||||
[]
|
||||
);
|
||||
|
@ -1,19 +1,15 @@
|
||||
<?php
|
||||
|
||||
return \Symfony\Component\VarExporter\Internal\Configurator::pop(
|
||||
\Symfony\Component\VarExporter\Internal\Registry::push([
|
||||
\Symfony\Component\VarExporter\Internal\Registry::$reflectors[\Symfony\Component\VarExporter\Tests\MyCloneable::class] ?? \Symfony\Component\VarExporter\Internal\Registry::getClassReflector(\Symfony\Component\VarExporter\Tests\MyCloneable::class, true, false),
|
||||
\Symfony\Component\VarExporter\Internal\Registry::$reflectors[\Symfony\Component\VarExporter\Tests\MyNotCloneable::class] ?? \Symfony\Component\VarExporter\Internal\Registry::getClassReflector(\Symfony\Component\VarExporter\Tests\MyNotCloneable::class, true, false),
|
||||
], [
|
||||
\Symfony\Component\VarExporter\Internal\Registry::$reflectors[\Symfony\Component\VarExporter\Tests\MyCloneable::class]->newInstanceWithoutConstructor(),
|
||||
\Symfony\Component\VarExporter\Internal\Registry::$reflectors[\Symfony\Component\VarExporter\Tests\MyNotCloneable::class]->newInstanceWithoutConstructor(),
|
||||
], [
|
||||
]),
|
||||
return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate(
|
||||
$o = [
|
||||
(($f =& \Symfony\Component\VarExporter\Internal\Registry::$factories)[\Symfony\Component\VarExporter\Tests\MyCloneable::class] ?? \Symfony\Component\VarExporter\Internal\Registry::f(\Symfony\Component\VarExporter\Tests\MyCloneable::class, true))(),
|
||||
($f[\Symfony\Component\VarExporter\Tests\MyNotCloneable::class] ?? \Symfony\Component\VarExporter\Internal\Registry::f(\Symfony\Component\VarExporter\Tests\MyNotCloneable::class, true))(),
|
||||
],
|
||||
null,
|
||||
[],
|
||||
[
|
||||
\Symfony\Component\VarExporter\Internal\Registry::$objects[0],
|
||||
\Symfony\Component\VarExporter\Internal\Registry::$objects[1],
|
||||
$o[0],
|
||||
$o[1],
|
||||
],
|
||||
[]
|
||||
);
|
||||
|
@ -1,15 +1,12 @@
|
||||
<?php
|
||||
|
||||
return \Symfony\Component\VarExporter\Internal\Configurator::pop(
|
||||
\Symfony\Component\VarExporter\Internal\Registry::push([
|
||||
\Symfony\Component\VarExporter\Internal\Registry::$reflectors[\DateTime::class] ?? \Symfony\Component\VarExporter\Internal\Registry::getClassReflector(\DateTime::class, true, true),
|
||||
], [
|
||||
clone \Symfony\Component\VarExporter\Internal\Registry::$prototypes[\DateTime::class],
|
||||
], [
|
||||
]),
|
||||
return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate(
|
||||
$o = [
|
||||
clone (\Symfony\Component\VarExporter\Internal\Registry::$prototypes[\DateTime::class] ?? \Symfony\Component\VarExporter\Internal\Registry::p(\DateTime::class, true)),
|
||||
],
|
||||
null,
|
||||
[
|
||||
\DateTime::class => [
|
||||
'*' => [
|
||||
'date' => [
|
||||
'1970-01-01 00:00:00.000000',
|
||||
],
|
||||
@ -21,7 +18,7 @@ return \Symfony\Component\VarExporter\Internal\Configurator::pop(
|
||||
],
|
||||
],
|
||||
],
|
||||
\Symfony\Component\VarExporter\Internal\Registry::$objects[0],
|
||||
$o[0],
|
||||
[
|
||||
1 => 0,
|
||||
]
|
||||
|
30
src/Symfony/Component/VarExporter/Tests/Fixtures/error.php
Normal file
30
src/Symfony/Component/VarExporter/Tests/Fixtures/error.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate(
|
||||
$o = [
|
||||
(\Symfony\Component\VarExporter\Internal\Registry::$factories[\Error::class] ?? \Symfony\Component\VarExporter\Internal\Registry::f(\Error::class, true))(),
|
||||
],
|
||||
null,
|
||||
[
|
||||
\TypeError::class => [
|
||||
'file' => [
|
||||
\dirname(__DIR__).\DIRECTORY_SEPARATOR.'VarExporterTest.php',
|
||||
],
|
||||
'line' => [
|
||||
234,
|
||||
],
|
||||
],
|
||||
\Error::class => [
|
||||
'trace' => [
|
||||
[
|
||||
'file' => \dirname(__DIR__).\DIRECTORY_SEPARATOR.'VarExporterTest.php',
|
||||
'line' => 123,
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
$o[0],
|
||||
[
|
||||
1 => 0,
|
||||
]
|
||||
);
|
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
[
|
||||
123,
|
||||
],
|
||||
];
|
@ -1,15 +1,16 @@
|
||||
<?php
|
||||
|
||||
return \Symfony\Component\VarExporter\Internal\Configurator::pop(
|
||||
\Symfony\Component\VarExporter\Internal\Registry::push([], [], []),
|
||||
return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate(
|
||||
$o = [],
|
||||
[
|
||||
\Symfony\Component\VarExporter\Internal\Registry::$references[1] = [
|
||||
&\Symfony\Component\VarExporter\Internal\Registry::$references[1],
|
||||
$r = [],
|
||||
$r[1] = [
|
||||
&$r[1],
|
||||
],
|
||||
],
|
||||
[],
|
||||
[
|
||||
&\Symfony\Component\VarExporter\Internal\Registry::$references[1],
|
||||
&$r[1],
|
||||
],
|
||||
[]
|
||||
);
|
||||
|
@ -1,20 +1,18 @@
|
||||
<?php
|
||||
|
||||
return \Symfony\Component\VarExporter\Internal\Configurator::pop(
|
||||
\Symfony\Component\VarExporter\Internal\Registry::push([
|
||||
\Symfony\Component\VarExporter\Internal\Registry::$reflectors[\stdClass::class] ?? \Symfony\Component\VarExporter\Internal\Registry::getClassReflector(\stdClass::class, true, true),
|
||||
], [
|
||||
clone \Symfony\Component\VarExporter\Internal\Registry::$prototypes[\stdClass::class],
|
||||
], [
|
||||
]),
|
||||
return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate(
|
||||
$o = [
|
||||
clone (\Symfony\Component\VarExporter\Internal\Registry::$prototypes[\stdClass::class] ?? \Symfony\Component\VarExporter\Internal\Registry::p(\stdClass::class, true)),
|
||||
],
|
||||
[
|
||||
\Symfony\Component\VarExporter\Internal\Registry::$references[1] = \Symfony\Component\VarExporter\Internal\Registry::$objects[0],
|
||||
$r = [],
|
||||
$r[1] = $o[0],
|
||||
],
|
||||
[],
|
||||
[
|
||||
&\Symfony\Component\VarExporter\Internal\Registry::$references[1],
|
||||
&\Symfony\Component\VarExporter\Internal\Registry::$references[1],
|
||||
\Symfony\Component\VarExporter\Internal\Registry::$objects[0],
|
||||
&$r[1],
|
||||
&$r[1],
|
||||
$o[0],
|
||||
],
|
||||
[]
|
||||
);
|
||||
|
@ -1,11 +1,11 @@
|
||||
<?php
|
||||
|
||||
return \Symfony\Component\VarExporter\Internal\Configurator::pop(
|
||||
\Symfony\Component\VarExporter\Internal\Registry::push([], [], [
|
||||
return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate(
|
||||
$o = \Symfony\Component\VarExporter\Internal\Registry::unserialize([], [
|
||||
'O:20:"SomeNotExistingClass":0:{}',
|
||||
]),
|
||||
null,
|
||||
[],
|
||||
\Symfony\Component\VarExporter\Internal\Registry::$objects[0],
|
||||
$o[0],
|
||||
[]
|
||||
);
|
||||
|
@ -1,34 +1,26 @@
|
||||
<?php
|
||||
|
||||
return \Symfony\Component\VarExporter\Internal\Configurator::pop(
|
||||
\Symfony\Component\VarExporter\Internal\Registry::push([
|
||||
\Symfony\Component\VarExporter\Internal\Registry::$reflectors[\Symfony\Component\VarExporter\Tests\MyPrivateValue::class] ?? \Symfony\Component\VarExporter\Internal\Registry::getClassReflector(\Symfony\Component\VarExporter\Tests\MyPrivateValue::class, true, true),
|
||||
\Symfony\Component\VarExporter\Internal\Registry::$reflectors[\Symfony\Component\VarExporter\Tests\MyPrivateChildValue::class] ?? \Symfony\Component\VarExporter\Internal\Registry::getClassReflector(\Symfony\Component\VarExporter\Tests\MyPrivateChildValue::class, true, true),
|
||||
], [
|
||||
clone \Symfony\Component\VarExporter\Internal\Registry::$prototypes[\Symfony\Component\VarExporter\Tests\MyPrivateValue::class],
|
||||
clone \Symfony\Component\VarExporter\Internal\Registry::$prototypes[\Symfony\Component\VarExporter\Tests\MyPrivateChildValue::class],
|
||||
], [
|
||||
]),
|
||||
return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate(
|
||||
$o = [
|
||||
clone (($p =& \Symfony\Component\VarExporter\Internal\Registry::$prototypes)[\Symfony\Component\VarExporter\Tests\MyPrivateValue::class] ?? \Symfony\Component\VarExporter\Internal\Registry::p(\Symfony\Component\VarExporter\Tests\MyPrivateValue::class, true)),
|
||||
clone ($p[\Symfony\Component\VarExporter\Tests\MyPrivateChildValue::class] ?? \Symfony\Component\VarExporter\Internal\Registry::p(\Symfony\Component\VarExporter\Tests\MyPrivateChildValue::class, true)),
|
||||
],
|
||||
null,
|
||||
[
|
||||
\Symfony\Component\VarExporter\Tests\MyPrivateValue::class => [
|
||||
'prot' => [
|
||||
123,
|
||||
123,
|
||||
],
|
||||
'priv' => [
|
||||
234,
|
||||
234,
|
||||
],
|
||||
],
|
||||
\Symfony\Component\VarExporter\Tests\MyPrivateChildValue::class => [
|
||||
'prot' => [
|
||||
1 => 123,
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
\Symfony\Component\VarExporter\Internal\Registry::$objects[0],
|
||||
\Symfony\Component\VarExporter\Internal\Registry::$objects[1],
|
||||
$o[0],
|
||||
$o[1],
|
||||
],
|
||||
[]
|
||||
);
|
||||
|
@ -1,14 +1,14 @@
|
||||
<?php
|
||||
|
||||
return \Symfony\Component\VarExporter\Internal\Configurator::pop(
|
||||
\Symfony\Component\VarExporter\Internal\Registry::push([], [], [
|
||||
return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate(
|
||||
$o = \Symfony\Component\VarExporter\Internal\Registry::unserialize([], [
|
||||
'C:50:"Symfony\\Component\\VarExporter\\Tests\\MySerializable":3:{123}',
|
||||
]),
|
||||
null,
|
||||
[],
|
||||
[
|
||||
\Symfony\Component\VarExporter\Internal\Registry::$objects[0],
|
||||
\Symfony\Component\VarExporter\Internal\Registry::$objects[0],
|
||||
$o[0],
|
||||
$o[0],
|
||||
],
|
||||
[]
|
||||
);
|
||||
|
@ -1,25 +1,21 @@
|
||||
<?php
|
||||
|
||||
return \Symfony\Component\VarExporter\Internal\Configurator::pop(
|
||||
\Symfony\Component\VarExporter\Internal\Registry::push([
|
||||
\Symfony\Component\VarExporter\Internal\Registry::$reflectors[\SplObjectStorage::class] ?? \Symfony\Component\VarExporter\Internal\Registry::getClassReflector(\SplObjectStorage::class, true, true),
|
||||
\Symfony\Component\VarExporter\Internal\Registry::$reflectors[\stdClass::class] ?? \Symfony\Component\VarExporter\Internal\Registry::getClassReflector(\stdClass::class, true, true),
|
||||
], [
|
||||
clone \Symfony\Component\VarExporter\Internal\Registry::$prototypes[\SplObjectStorage::class],
|
||||
clone \Symfony\Component\VarExporter\Internal\Registry::$prototypes[\stdClass::class],
|
||||
], [
|
||||
]),
|
||||
return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate(
|
||||
$o = [
|
||||
clone (($p =& \Symfony\Component\VarExporter\Internal\Registry::$prototypes)[\SplObjectStorage::class] ?? \Symfony\Component\VarExporter\Internal\Registry::p(\SplObjectStorage::class, true)),
|
||||
clone ($p[\stdClass::class] ?? \Symfony\Component\VarExporter\Internal\Registry::p(\stdClass::class, true)),
|
||||
],
|
||||
null,
|
||||
[
|
||||
\SplObjectStorage::class => [
|
||||
"\0" => [
|
||||
[
|
||||
\Symfony\Component\VarExporter\Internal\Registry::$objects[1],
|
||||
$o[1],
|
||||
345,
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
\Symfony\Component\VarExporter\Internal\Registry::$objects[0],
|
||||
$o[0],
|
||||
[]
|
||||
);
|
||||
|
@ -1,28 +1,28 @@
|
||||
<?php
|
||||
|
||||
return \Symfony\Component\VarExporter\Internal\Configurator::pop(
|
||||
\Symfony\Component\VarExporter\Internal\Registry::push([
|
||||
\Symfony\Component\VarExporter\Internal\Registry::$reflectors[\Symfony\Component\VarExporter\Tests\MyWakeup::class] ?? \Symfony\Component\VarExporter\Internal\Registry::getClassReflector(\Symfony\Component\VarExporter\Tests\MyWakeup::class, true, true),
|
||||
], [
|
||||
clone \Symfony\Component\VarExporter\Internal\Registry::$prototypes[\Symfony\Component\VarExporter\Tests\MyWakeup::class],
|
||||
clone \Symfony\Component\VarExporter\Internal\Registry::$prototypes[\Symfony\Component\VarExporter\Tests\MyWakeup::class],
|
||||
], [
|
||||
]),
|
||||
return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate(
|
||||
$o = [
|
||||
clone (($p =& \Symfony\Component\VarExporter\Internal\Registry::$prototypes)[\Symfony\Component\VarExporter\Tests\MyWakeup::class] ?? \Symfony\Component\VarExporter\Internal\Registry::p(\Symfony\Component\VarExporter\Tests\MyWakeup::class, true)),
|
||||
clone $p[\Symfony\Component\VarExporter\Tests\MyWakeup::class],
|
||||
],
|
||||
null,
|
||||
[
|
||||
\Symfony\Component\VarExporter\Tests\MyWakeup::class => [
|
||||
'*' => [
|
||||
'sub' => [
|
||||
\Symfony\Component\VarExporter\Internal\Registry::$objects[1],
|
||||
$o[1],
|
||||
123,
|
||||
],
|
||||
'bis' => [
|
||||
1 => 123,
|
||||
],
|
||||
'baz' => [
|
||||
1 => 123,
|
||||
],
|
||||
],
|
||||
],
|
||||
\Symfony\Component\VarExporter\Internal\Registry::$objects[0],
|
||||
$o[0],
|
||||
[
|
||||
1 => 1,
|
||||
2 => 0,
|
||||
0,
|
||||
]
|
||||
);
|
||||
|
@ -12,9 +12,9 @@
|
||||
namespace Symfony\Component\VarExporter\Tests;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\VarDumper\Test\VarDumperTestTrait;
|
||||
use Symfony\Component\VarExporter\Internal\Registry;
|
||||
use Symfony\Component\VarExporter\VarExporter;
|
||||
use Symfony\Component\VarDumper\Test\VarDumperTestTrait;
|
||||
|
||||
class VarExporterTest extends TestCase
|
||||
{
|
||||
@ -28,7 +28,7 @@ class VarExporterTest extends TestCase
|
||||
{
|
||||
$unserializeCallback = ini_set('unserialize_callback_func', 'var_dump');
|
||||
try {
|
||||
Registry::push(array(), array(), array('O:20:"SomeNotExistingClass":0:{}'));
|
||||
Registry::unserialize(array(), array('O:20:"SomeNotExistingClass":0:{}'));
|
||||
} finally {
|
||||
$this->assertSame('var_dump', ini_set('unserialize_callback_func', $unserializeCallback));
|
||||
}
|
||||
@ -80,10 +80,11 @@ class VarExporterTest extends TestCase
|
||||
$this->assertSame($serializedValue, serialize($value));
|
||||
|
||||
$dump = "<?php\n\nreturn ".$marshalledValue.";\n";
|
||||
$dump = str_replace(var_export(__FILE__, true), "\\dirname(__DIR__).\\DIRECTORY_SEPARATOR.'VarExporterTest.php'", $dump);
|
||||
$fixtureFile = __DIR__.'/Fixtures/'.$testName.'.php';
|
||||
$this->assertStringEqualsFile($fixtureFile, $dump);
|
||||
|
||||
if ('incomplete-class' === $testName) {
|
||||
if ('incomplete-class' === $testName || 'external-references' === $testName) {
|
||||
return;
|
||||
}
|
||||
$marshalledValue = include $fixtureFile;
|
||||
@ -146,6 +147,24 @@ class VarExporterTest extends TestCase
|
||||
$value[0] = &$value;
|
||||
|
||||
yield array('hard-references-recursive', $value);
|
||||
|
||||
static $value = array(123);
|
||||
|
||||
yield array('external-references', array(&$value), true);
|
||||
|
||||
unset($value);
|
||||
|
||||
$value = new \Error();
|
||||
|
||||
$r = new \ReflectionProperty('Error', 'trace');
|
||||
$r->setAccessible(true);
|
||||
$r->setValue($value, array('file' => __FILE__, 'line' => 123));
|
||||
|
||||
$r = new \ReflectionProperty('Error', 'line');
|
||||
$r->setAccessible(true);
|
||||
$r->setValue($value, 234);
|
||||
|
||||
yield array('error', $value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,9 +11,8 @@
|
||||
|
||||
namespace Symfony\Component\VarExporter;
|
||||
|
||||
use Symfony\Component\VarExporter\Internal\Configurator;
|
||||
use Symfony\Component\VarExporter\Internal\Exporter;
|
||||
use Symfony\Component\VarExporter\Internal\Reference;
|
||||
use Symfony\Component\VarExporter\Internal\Hydrator;
|
||||
use Symfony\Component\VarExporter\Internal\Registry;
|
||||
use Symfony\Component\VarExporter\Internal\Values;
|
||||
|
||||
@ -56,8 +55,10 @@ final class VarExporter
|
||||
} finally {
|
||||
$references = array();
|
||||
foreach ($refsPool as $i => $v) {
|
||||
if ($v[0]->count) {
|
||||
$references[1 + $i] = $v[2];
|
||||
}
|
||||
$v[0] = $v[1];
|
||||
$references[1 + $i] = $v[2];
|
||||
}
|
||||
}
|
||||
|
||||
@ -85,7 +86,11 @@ final class VarExporter
|
||||
}
|
||||
}
|
||||
|
||||
$value = new Configurator(new Registry($classes), $references ? new Values($references) : null, $properties, $value, $wakeups);
|
||||
if ($classes || $references) {
|
||||
$value = new Hydrator(new Registry($classes), $references ? new Values($references) : null, $properties, $value, $wakeups);
|
||||
} else {
|
||||
$isStaticValue = true;
|
||||
}
|
||||
|
||||
return Exporter::export($value);
|
||||
}
|
||||
|
Reference in New Issue
Block a user