Skip to content

Commit 373dad3

Browse files
bug symfony#28371 [VarExporter] fix exporting objects that mutate on __sleep() (nicolas-grekas)
This PR was merged into the 4.2-dev branch. Discussion ---------- [VarExporter] fix exporting objects that mutate on __sleep() | Q | A | ------------- | --- | Branch? | master | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | symfony#28352 | License | MIT | Doc PR | - Commits ------- 36e412f [VarExporter] fix exporting objects that mutate on __sleep()
2 parents 150e3e1 + 36e412f commit 373dad3

File tree

4 files changed

+44
-10
lines changed

4 files changed

+44
-10
lines changed

src/Symfony/Component/VarExporter/Internal/Exporter.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@ public static function prepare($values, $objectsPool, &$refsPool, &$objectsCount
8080
// Might throw Exception("Serialization of '...' is not allowed")
8181
Registry::getClassReflector($class);
8282
serialize(Registry::$prototypes[$class]);
83+
if (\method_exists($class, '__sleep')) {
84+
Registry::getClassReflector($class, Registry::$instantiableWithoutConstructor[$class], Registry::$cloneable[$class]);
85+
}
8386
}
8487
$reflector = Registry::$reflectors[$class];
8588
$proto = Registry::$prototypes[$class];
@@ -110,6 +113,11 @@ public static function prepare($values, $objectsPool, &$refsPool, &$objectsCount
110113
$value = null;
111114
goto handle_value;
112115
}
116+
foreach ($sleep as $name) {
117+
if (\property_exists($value, $name) && !$reflector->hasProperty($name)) {
118+
$arrayValue[$name] = $value->$name;
119+
}
120+
}
113121
$sleep = array_flip($sleep);
114122
}
115123

src/Symfony/Component/VarExporter/Internal/Registry.php

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -74,14 +74,9 @@ public static function getClassReflector($class, $instantiableWithoutConstructor
7474
}
7575
}
7676

77-
if (null !== $cloneable) {
78-
self::$prototypes[$class] = $proto;
79-
self::$cloneable[$class] = $cloneable;
80-
81-
return self::$reflectors[$class] = $reflector;
82-
}
83-
84-
if ($proto instanceof \Reflector || $proto instanceof \ReflectionGenerator || $proto instanceof \ReflectionType || $proto instanceof \IteratorIterator || $proto instanceof \RecursiveIteratorIterator) {
77+
if (null !== self::$cloneable[$class] = $cloneable) {
78+
// no-op
79+
} elseif ($proto instanceof \Reflector || $proto instanceof \ReflectionGenerator || $proto instanceof \ReflectionType || $proto instanceof \IteratorIterator || $proto instanceof \RecursiveIteratorIterator) {
8580
if (!$proto instanceof \Serializable && !\method_exists($proto, '__wakeup')) {
8681
throw new \Exception(sprintf("Serialization of '%s' is not allowed", $class));
8782
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate(
4+
$o = [
5+
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)),
6+
],
7+
null,
8+
[
9+
'*' => [
10+
'good' => [
11+
'night',
12+
],
13+
],
14+
],
15+
$o[0],
16+
[]
17+
);

src/Symfony/Component/VarExporter/Tests/VarExporterTest.php

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,14 @@ public function provideFailingSerialization()
7272
*/
7373
public function testMarshall(string $testName, $value, bool $staticValueExpected = false)
7474
{
75-
$serializedValue = serialize($value);
75+
$dumpedValue = $this->getDump($value);
7676
$isStaticValue = true;
7777
$marshalledValue = VarExporter::export($value, $isStaticValue);
7878

7979
$this->assertSame($staticValueExpected, $isStaticValue);
80-
$this->assertSame($serializedValue, serialize($value));
80+
if ('var-on-sleep' !== $testName) {
81+
$this->assertDumpEquals($dumpedValue, $value);
82+
}
8183

8284
$dump = "<?php\n\nreturn ".$marshalledValue.";\n";
8385
$dump = str_replace(var_export(__FILE__, true), "\\dirname(__DIR__).\\DIRECTORY_SEPARATOR.'VarExporterTest.php'", $dump);
@@ -165,6 +167,8 @@ public function provideMarshall()
165167
$r->setValue($value, 234);
166168

167169
yield array('error', $value);
170+
171+
yield array('var-on-sleep', new GoodNight());
168172
}
169173
}
170174

@@ -248,3 +252,13 @@ public function setFlags($flags)
248252
throw new \BadMethodCallException('Calling MyArrayObject::setFlags() is forbidden');
249253
}
250254
}
255+
256+
class GoodNight
257+
{
258+
public function __sleep()
259+
{
260+
$this->good = 'night';
261+
262+
return array('good');
263+
}
264+
}

0 commit comments

Comments
 (0)