From 36e412fdfc1af60c8af53c0f7cfe9dd15ef1fc36 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 5 Sep 2018 15:34:16 +0200 Subject: [PATCH] [VarExporter] fix exporting objects that mutate on __sleep() --- .../VarExporter/Internal/Exporter.php | 8 ++++++++ .../VarExporter/Internal/Registry.php | 11 +++-------- .../Tests/Fixtures/var-on-sleep.php | 17 +++++++++++++++++ .../VarExporter/Tests/VarExporterTest.php | 18 ++++++++++++++++-- 4 files changed, 44 insertions(+), 10 deletions(-) create mode 100644 src/Symfony/Component/VarExporter/Tests/Fixtures/var-on-sleep.php diff --git a/src/Symfony/Component/VarExporter/Internal/Exporter.php b/src/Symfony/Component/VarExporter/Internal/Exporter.php index 69d1259e16..b15e06af96 100644 --- a/src/Symfony/Component/VarExporter/Internal/Exporter.php +++ b/src/Symfony/Component/VarExporter/Internal/Exporter.php @@ -80,6 +80,9 @@ class Exporter // Might throw Exception("Serialization of '...' is not allowed") Registry::getClassReflector($class); serialize(Registry::$prototypes[$class]); + if (\method_exists($class, '__sleep')) { + Registry::getClassReflector($class, Registry::$instantiableWithoutConstructor[$class], Registry::$cloneable[$class]); + } } $reflector = Registry::$reflectors[$class]; $proto = Registry::$prototypes[$class]; @@ -110,6 +113,11 @@ class Exporter $value = null; goto handle_value; } + foreach ($sleep as $name) { + if (\property_exists($value, $name) && !$reflector->hasProperty($name)) { + $arrayValue[$name] = $value->$name; + } + } $sleep = array_flip($sleep); } diff --git a/src/Symfony/Component/VarExporter/Internal/Registry.php b/src/Symfony/Component/VarExporter/Internal/Registry.php index f09df43681..bf943d5e2b 100644 --- a/src/Symfony/Component/VarExporter/Internal/Registry.php +++ b/src/Symfony/Component/VarExporter/Internal/Registry.php @@ -74,14 +74,9 @@ class Registry } } - if (null !== $cloneable) { - self::$prototypes[$class] = $proto; - self::$cloneable[$class] = $cloneable; - - return self::$reflectors[$class] = $reflector; - } - - if ($proto instanceof \Reflector || $proto instanceof \ReflectionGenerator || $proto instanceof \ReflectionType || $proto instanceof \IteratorIterator || $proto instanceof \RecursiveIteratorIterator) { + if (null !== self::$cloneable[$class] = $cloneable) { + // no-op + } elseif ($proto instanceof \Reflector || $proto instanceof \ReflectionGenerator || $proto instanceof \ReflectionType || $proto instanceof \IteratorIterator || $proto instanceof \RecursiveIteratorIterator) { if (!$proto instanceof \Serializable && !\method_exists($proto, '__wakeup')) { throw new \Exception(sprintf("Serialization of '%s' is not allowed", $class)); } diff --git a/src/Symfony/Component/VarExporter/Tests/Fixtures/var-on-sleep.php b/src/Symfony/Component/VarExporter/Tests/Fixtures/var-on-sleep.php new file mode 100644 index 0000000000..b013ef14ef --- /dev/null +++ b/src/Symfony/Component/VarExporter/Tests/Fixtures/var-on-sleep.php @@ -0,0 +1,17 @@ + [ + 'good' => [ + 'night', + ], + ], + ], + $o[0], + [] +); diff --git a/src/Symfony/Component/VarExporter/Tests/VarExporterTest.php b/src/Symfony/Component/VarExporter/Tests/VarExporterTest.php index 2ca437d347..b8f4db09d6 100644 --- a/src/Symfony/Component/VarExporter/Tests/VarExporterTest.php +++ b/src/Symfony/Component/VarExporter/Tests/VarExporterTest.php @@ -72,12 +72,14 @@ class VarExporterTest extends TestCase */ public function testMarshall(string $testName, $value, bool $staticValueExpected = false) { - $serializedValue = serialize($value); + $dumpedValue = $this->getDump($value); $isStaticValue = true; $marshalledValue = VarExporter::export($value, $isStaticValue); $this->assertSame($staticValueExpected, $isStaticValue); - $this->assertSame($serializedValue, serialize($value)); + if ('var-on-sleep' !== $testName) { + $this->assertDumpEquals($dumpedValue, $value); + } $dump = "setValue($value, 234); 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'); } } + +class GoodNight +{ + public function __sleep() + { + $this->good = 'night'; + + return array('good'); + } +}