From fe83e0e45718c5f5918785ffee7abbe14377022a Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 24 Sep 2021 15:17:06 +0200 Subject: [PATCH] [VarDumper] fix dumping typed references from properties --- .../Component/VarDumper/Cloner/VarCloner.php | 47 ++++++++++------ .../VarDumper/Tests/Cloner/VarClonerTest.php | 53 +++++++++++++++++-- .../VarDumper/Tests/Fixtures/Php74.php | 2 + 3 files changed, 82 insertions(+), 20 deletions(-) diff --git a/src/Symfony/Component/VarDumper/Cloner/VarCloner.php b/src/Symfony/Component/VarDumper/Cloner/VarCloner.php index 6a9002137b7c9..cd6e7dcab4804 100644 --- a/src/Symfony/Component/VarDumper/Cloner/VarCloner.php +++ b/src/Symfony/Component/VarDumper/Cloner/VarCloner.php @@ -82,29 +82,39 @@ protected function doClone($var) // $v is the original value or a stub object in case of hard references if (\PHP_VERSION_ID >= 70400) { - $zvalIsRef = null !== \ReflectionReference::fromArrayElement($vals, $k); + $zvalRef = ($r = \ReflectionReference::fromArrayElement($vals, $k)) ? $r->getId() : null; } else { $refs[$k] = $cookie; - $zvalIsRef = $vals[$k] === $cookie; + $zvalRef = $vals[$k] === $cookie; } - if ($zvalIsRef) { + if ($zvalRef) { $vals[$k] = &$stub; // Break hard references to make $queue completely unset($stub); // independent from the original structure - if ($v instanceof Stub && isset($hardRefs[spl_object_id($v)])) { - $vals[$k] = $refs[$k] = $v; + if (\PHP_VERSION_ID >= 70400 ? null !== $vals[$k] = $hardRefs[$zvalRef] ?? null : $v instanceof Stub && isset($hardRefs[spl_object_id($v)])) { + if (\PHP_VERSION_ID >= 70400) { + $v = $vals[$k]; + } else { + $refs[$k] = $vals[$k] = $v; + } if ($v->value instanceof Stub && (Stub::TYPE_OBJECT === $v->value->type || Stub::TYPE_RESOURCE === $v->value->type)) { ++$v->value->refCount; } ++$v->refCount; continue; } - $refs[$k] = $vals[$k] = new Stub(); - $refs[$k]->value = $v; - $h = spl_object_id($refs[$k]); - $hardRefs[$h] = &$refs[$k]; - $values[$h] = $v; + $vals[$k] = new Stub(); + $vals[$k]->value = $v; $vals[$k]->handle = ++$refsCounter; + + if (\PHP_VERSION_ID >= 70400) { + $hardRefs[$zvalRef] = $vals[$k]; + } else { + $refs[$k] = $vals[$k]; + $h = spl_object_id($refs[$k]); + $hardRefs[$h] = &$refs[$k]; + $values[$h] = $v; + } } // Create $stub when the original value $v can not be used directly // If $v is a nested structure, put that structure in array $a @@ -163,12 +173,17 @@ protected function doClone($var) unset($v[$gid]); $a = []; foreach ($v as $gk => &$gv) { - if ($v === $gv) { + if ($v === $gv && (\PHP_VERSION_ID < 70400 || !isset($hardRefs[\ReflectionReference::fromArrayElement($v, $gk)->getId()]))) { unset($v); $v = new Stub(); $v->value = [$v->cut = \count($gv), Stub::TYPE_ARRAY => 0]; $v->handle = -1; - $gv = &$hardRefs[spl_object_id($v)]; + if (\PHP_VERSION_ID >= 70400) { + $gv = &$a[$gk]; + $hardRefs[\ReflectionReference::fromArrayElement($a, $gk)->getId()] = &$gv; + } else { + $gv = &$hardRefs[spl_object_id($v)]; + } $gv = $v; } @@ -270,10 +285,12 @@ protected function doClone($var) } } - if ($zvalIsRef) { - $refs[$k]->value = $stub; - } else { + if (!$zvalRef) { $vals[$k] = $stub; + } elseif (\PHP_VERSION_ID >= 70400) { + $hardRefs[$zvalRef]->value = $stub; + } else { + $refs[$k]->value = $stub; } } diff --git a/src/Symfony/Component/VarDumper/Tests/Cloner/VarClonerTest.php b/src/Symfony/Component/VarDumper/Tests/Cloner/VarClonerTest.php index a9518444db9c2..fed2d669a7654 100644 --- a/src/Symfony/Component/VarDumper/Tests/Cloner/VarClonerTest.php +++ b/src/Symfony/Component/VarDumper/Tests/Cloner/VarClonerTest.php @@ -499,12 +499,55 @@ public function testPhp74() [p1] => 123 [p2] => Symfony\Component\VarDumper\Cloner\Stub Object ( - [type] => 4 - [class] => stdClass - [value] => + [type] => 1 + [class] => + [value] => Symfony\Component\VarDumper\Cloner\Stub Object + ( + [type] => 4 + [class] => stdClass + [value] => + [cut] => 0 + [handle] => %i + [refCount] => 1 + [position] => 0 + [attr] => Array + ( + ) + + ) + [cut] => 0 - [handle] => %i - [refCount] => 0 + [handle] => 1 + [refCount] => 1 + [position] => 0 + [attr] => Array + ( + ) + + ) + + [p3] => Symfony\Component\VarDumper\Cloner\Stub Object + ( + [type] => 1 + [class] => + [value] => Symfony\Component\VarDumper\Cloner\Stub Object + ( + [type] => 4 + [class] => stdClass + [value] => + [cut] => 0 + [handle] => %i + [refCount] => 1 + [position] => 0 + [attr] => Array + ( + ) + + ) + + [cut] => 0 + [handle] => 1 + [refCount] => 1 [position] => 0 [attr] => Array ( diff --git a/src/Symfony/Component/VarDumper/Tests/Fixtures/Php74.php b/src/Symfony/Component/VarDumper/Tests/Fixtures/Php74.php index 724fbeb7bdb6e..8bd4c496a1715 100644 --- a/src/Symfony/Component/VarDumper/Tests/Fixtures/Php74.php +++ b/src/Symfony/Component/VarDumper/Tests/Fixtures/Php74.php @@ -6,9 +6,11 @@ class Php74 { public $p1 = 123; public \stdClass $p2; + public \stdClass $p3; public function __construct() { $this->p2 = new \stdClass(); + $this->p3 = &$this->p2; } }