[VarExporter] fix exporting objects that mutate on __sleep()
This commit is contained in:
parent
e4d7c74845
commit
36e412fdfc
@ -80,6 +80,9 @@ class Exporter
|
|||||||
// Might throw Exception("Serialization of '...' is not allowed")
|
// Might throw Exception("Serialization of '...' is not allowed")
|
||||||
Registry::getClassReflector($class);
|
Registry::getClassReflector($class);
|
||||||
serialize(Registry::$prototypes[$class]);
|
serialize(Registry::$prototypes[$class]);
|
||||||
|
if (\method_exists($class, '__sleep')) {
|
||||||
|
Registry::getClassReflector($class, Registry::$instantiableWithoutConstructor[$class], Registry::$cloneable[$class]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$reflector = Registry::$reflectors[$class];
|
$reflector = Registry::$reflectors[$class];
|
||||||
$proto = Registry::$prototypes[$class];
|
$proto = Registry::$prototypes[$class];
|
||||||
@ -110,6 +113,11 @@ class Exporter
|
|||||||
$value = null;
|
$value = null;
|
||||||
goto handle_value;
|
goto handle_value;
|
||||||
}
|
}
|
||||||
|
foreach ($sleep as $name) {
|
||||||
|
if (\property_exists($value, $name) && !$reflector->hasProperty($name)) {
|
||||||
|
$arrayValue[$name] = $value->$name;
|
||||||
|
}
|
||||||
|
}
|
||||||
$sleep = array_flip($sleep);
|
$sleep = array_flip($sleep);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,14 +74,9 @@ class Registry
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null !== $cloneable) {
|
if (null !== self::$cloneable[$class] = $cloneable) {
|
||||||
self::$prototypes[$class] = $proto;
|
// no-op
|
||||||
self::$cloneable[$class] = $cloneable;
|
} elseif ($proto instanceof \Reflector || $proto instanceof \ReflectionGenerator || $proto instanceof \ReflectionType || $proto instanceof \IteratorIterator || $proto instanceof \RecursiveIteratorIterator) {
|
||||||
|
|
||||||
return self::$reflectors[$class] = $reflector;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($proto instanceof \Reflector || $proto instanceof \ReflectionGenerator || $proto instanceof \ReflectionType || $proto instanceof \IteratorIterator || $proto instanceof \RecursiveIteratorIterator) {
|
|
||||||
if (!$proto instanceof \Serializable && !\method_exists($proto, '__wakeup')) {
|
if (!$proto instanceof \Serializable && !\method_exists($proto, '__wakeup')) {
|
||||||
throw new \Exception(sprintf("Serialization of '%s' is not allowed", $class));
|
throw new \Exception(sprintf("Serialization of '%s' is not allowed", $class));
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate(
|
||||||
|
$o = [
|
||||||
|
clone (\Symfony\Component\VarExporter\Internal\Registry::$prototypes[\Symfony\Component\VarExporter\Tests\GoodNight::class] ?? \Symfony\Component\VarExporter\Internal\Registry::p(\Symfony\Component\VarExporter\Tests\GoodNight::class, true)),
|
||||||
|
],
|
||||||
|
null,
|
||||||
|
[
|
||||||
|
'*' => [
|
||||||
|
'good' => [
|
||||||
|
'night',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
$o[0],
|
||||||
|
[]
|
||||||
|
);
|
@ -72,12 +72,14 @@ class VarExporterTest extends TestCase
|
|||||||
*/
|
*/
|
||||||
public function testMarshall(string $testName, $value, bool $staticValueExpected = false)
|
public function testMarshall(string $testName, $value, bool $staticValueExpected = false)
|
||||||
{
|
{
|
||||||
$serializedValue = serialize($value);
|
$dumpedValue = $this->getDump($value);
|
||||||
$isStaticValue = true;
|
$isStaticValue = true;
|
||||||
$marshalledValue = VarExporter::export($value, $isStaticValue);
|
$marshalledValue = VarExporter::export($value, $isStaticValue);
|
||||||
|
|
||||||
$this->assertSame($staticValueExpected, $isStaticValue);
|
$this->assertSame($staticValueExpected, $isStaticValue);
|
||||||
$this->assertSame($serializedValue, serialize($value));
|
if ('var-on-sleep' !== $testName) {
|
||||||
|
$this->assertDumpEquals($dumpedValue, $value);
|
||||||
|
}
|
||||||
|
|
||||||
$dump = "<?php\n\nreturn ".$marshalledValue.";\n";
|
$dump = "<?php\n\nreturn ".$marshalledValue.";\n";
|
||||||
$dump = str_replace(var_export(__FILE__, true), "\\dirname(__DIR__).\\DIRECTORY_SEPARATOR.'VarExporterTest.php'", $dump);
|
$dump = str_replace(var_export(__FILE__, true), "\\dirname(__DIR__).\\DIRECTORY_SEPARATOR.'VarExporterTest.php'", $dump);
|
||||||
@ -165,6 +167,8 @@ class VarExporterTest extends TestCase
|
|||||||
$r->setValue($value, 234);
|
$r->setValue($value, 234);
|
||||||
|
|
||||||
yield array('error', $value);
|
yield array('error', $value);
|
||||||
|
|
||||||
|
yield array('var-on-sleep', new GoodNight());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -248,3 +252,13 @@ class MyArrayObject extends \ArrayObject
|
|||||||
throw new \BadMethodCallException('Calling MyArrayObject::setFlags() is forbidden');
|
throw new \BadMethodCallException('Calling MyArrayObject::setFlags() is forbidden');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class GoodNight
|
||||||
|
{
|
||||||
|
public function __sleep()
|
||||||
|
{
|
||||||
|
$this->good = 'night';
|
||||||
|
|
||||||
|
return array('good');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user