Skip to content

Commit

Permalink
[VarDumper] Fix serialization of stubs with null or uninitialized values
Browse files Browse the repository at this point in the history
  • Loading branch information
derrabus committed Feb 12, 2024
1 parent df4401f commit 18e3906
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 4 deletions.
25 changes: 25 additions & 0 deletions Cloner/Internal/NoDefault.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\VarDumper\Cloner\Internal;

/**
* Flags a typed property that has no default value.
*
* This dummy object is used to distinguish a property with a default value of null
* from a property that is uninitialized by default.
*
* @internal
*/
enum NoDefault
{
case NoDefault;
}
15 changes: 11 additions & 4 deletions Cloner/Stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

namespace Symfony\Component\VarDumper\Cloner;

use Symfony\Component\VarDumper\Cloner\Internal\NoDefault;

/**
* Represents the main properties of a PHP variable.
*
Expand Down Expand Up @@ -50,15 +52,20 @@ public function __sleep(): array
$properties = [];

if (!isset(self::$defaultProperties[$c = static::class])) {
self::$defaultProperties[$c] = get_class_vars($c);
$reflection = new \ReflectionClass($c);
self::$defaultProperties[$c] = [];

foreach ($reflection->getProperties() as $p) {
if ($p->isStatic()) {
continue;
}

foreach ((new \ReflectionClass($c))->getStaticProperties() as $k => $v) {
unset(self::$defaultProperties[$c][$k]);
self::$defaultProperties[$c][$p->name] = $p->hasDefaultValue() ? $p->getDefaultValue() : ($p->hasType() ? NoDefault::NoDefault : null);
}
}

foreach (self::$defaultProperties[$c] as $k => $v) {
if ($this->$k !== $v) {
if (NoDefault::NoDefault === $v || $this->$k !== $v) {
$properties[] = $k;
}
}
Expand Down
53 changes: 53 additions & 0 deletions Tests/Cloner/StubTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\VarDumper\Tests\Cloner;

use PHPUnit\Framework\TestCase;
use Symfony\Component\VarDumper\Cloner\Stub;

final class StubTest extends TestCase
{
public function testUnserializeNullValue()
{
$stub = new Stub();
$stub->value = null;

$stub = unserialize(serialize($stub));

self::assertNull($stub->value);
}

public function testUnserializeNullInTypedProperty()
{
$stub = new MyStub();
$stub->myProp = null;

$stub = unserialize(serialize($stub));

self::assertNull($stub->myProp);
}

public function testUninitializedStubPropertiesAreLeftUninitialized()
{
$stub = new MyStub();

$stub = unserialize(serialize($stub));

$r = new \ReflectionProperty(MyStub::class, 'myProp');
self::assertFalse($r->isInitialized($stub));
}
}

final class MyStub extends Stub
{
public mixed $myProp;
}

0 comments on commit 18e3906

Please sign in to comment.