Skip to content

Commit b8d03ca

Browse files
bug symfony#31303 [VarDumper] Use \ReflectionReference for determining if a key is a reference (php >= 7.4) (dorumd, nicolas-grekas)
This PR was merged into the 3.4 branch. Discussion ---------- [VarDumper] Use \ReflectionReference for determining if a key is a reference (php >= 7.4) | Q | A | ------------- | --- | Branch? | 3.4 | Bug fix? | no | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | symfony#31135 | License | MIT | Doc PR | - Prepare for PHP 7.4: use ReflectionReference in VarCloner Commits ------- 40f24ef [VarDumper] finish PHP 7.4 support and add tests e99a6b8 [VarDumper] Use \ReflectionReference for determining if a key is a reference (php >= 7.4)
2 parents bfe4e16 + 40f24ef commit b8d03ca

File tree

5 files changed

+103
-8
lines changed

5 files changed

+103
-8
lines changed

src/Symfony/Component/VarDumper/Caster/Caster.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,8 @@ public static function castObject($obj, $class, $hasDebugInfo = false)
6868
foreach ($a as $k => $v) {
6969
if (isset($k[0]) ? "\0" !== $k[0] : \PHP_VERSION_ID >= 70200) {
7070
if (!isset($publicProperties[$class])) {
71-
foreach (get_class_vars($class) as $prop => $v) {
72-
$publicProperties[$class][$prop] = true;
71+
foreach ((new \ReflectionClass($class))->getProperties(\ReflectionProperty::IS_PUBLIC) as $prop) {
72+
$publicProperties[$class][$prop->name] = true;
7373
}
7474
}
7575
if (!isset($publicProperties[$class][$k])) {

src/Symfony/Component/VarDumper/Cloner/Stub.php

+9-3
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,17 @@ public function __sleep()
4949
$properties = [];
5050

5151
if (!isset(self::$defaultProperties[$c = \get_class($this)])) {
52-
self::$defaultProperties[$c] = get_class_vars($c);
52+
$defaultProperties = get_class_vars($c);
5353

54-
foreach ((new \ReflectionClass($c))->getStaticProperties() as $k => $v) {
55-
unset(self::$defaultProperties[$c][$k]);
54+
foreach ((new \ReflectionClass($c))->getProperties(\ReflectionProperty::IS_PUBLIC) as $v) {
55+
if ($v->isStatic()) {
56+
unset($defaultProperties[$v->name]);
57+
} elseif (!isset($defaultProperties[$v->name])) {
58+
$defaultProperties[$v->name] = null;
59+
}
5660
}
61+
62+
self::$defaultProperties[$c] = $defaultProperties;
5763
}
5864

5965
foreach (self::$defaultProperties[$c] as $k => $v) {

src/Symfony/Component/VarDumper/Cloner/VarCloner.php

+10-3
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ protected function doClone($var)
4242
$currentDepth = 0; // Current tree depth
4343
$currentDepthFinalIndex = 0; // Final $queue index for current tree depth
4444
$minimumDepthReached = 0 === $minDepth; // Becomes true when minimum tree depth has been reached
45-
$cookie = (object) []; // Unique object used to detect hard references
45+
$cookie = (object) []; // Unique object used to detect hard references
4646
$a = null; // Array cast for nested structures
4747
$stub = null; // Stub capturing the main properties of an original item value
4848
// or null if the original value is used directly
@@ -86,8 +86,15 @@ protected function doClone($var)
8686
}
8787
foreach ($vals as $k => $v) {
8888
// $v is the original value or a stub object in case of hard references
89-
$refs[$k] = $cookie;
90-
if ($zvalIsRef = $vals[$k] === $cookie) {
89+
90+
if (\PHP_VERSION_ID >= 70400) {
91+
$zvalIsRef = null !== \ReflectionReference::fromArrayElement($vals, $k);
92+
} else {
93+
$refs[$k] = $cookie;
94+
$zvalIsRef = $vals[$k] === $cookie;
95+
}
96+
97+
if ($zvalIsRef) {
9198
$vals[$k] = &$stub; // Break hard references to make $queue completely
9299
unset($stub); // independent from the original structure
93100
if ($v instanceof Stub && isset($hardRefs[spl_object_hash($v)])) {

src/Symfony/Component/VarDumper/Tests/Cloner/VarClonerTest.php

+68
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use PHPUnit\Framework\TestCase;
1515
use Symfony\Component\VarDumper\Cloner\VarCloner;
16+
use Symfony\Component\VarDumper\Tests\Fixtures\Php74;
1617

1718
/**
1819
* @author Nicolas Grekas <p@tchwork.com>
@@ -431,6 +432,73 @@ public function testCaster()
431432
[useRefHandles:Symfony\Component\VarDumper\Cloner\Data:private] => -1
432433
)
433434
435+
EOTXT;
436+
$this->assertStringMatchesFormat($expected, print_r($clone, true));
437+
}
438+
439+
/**
440+
* @requires PHP 7.4
441+
*/
442+
public function testPhp74()
443+
{
444+
$data = new Php74();
445+
446+
$cloner = new VarCloner();
447+
$clone = $cloner->cloneVar($data);
448+
449+
$expected = <<<'EOTXT'
450+
Symfony\Component\VarDumper\Cloner\Data Object
451+
(
452+
[data:Symfony\Component\VarDumper\Cloner\Data:private] => Array
453+
(
454+
[0] => Array
455+
(
456+
[0] => Symfony\Component\VarDumper\Cloner\Stub Object
457+
(
458+
[type] => 4
459+
[class] => Symfony\Component\VarDumper\Tests\Fixtures\Php74
460+
[value] =>
461+
[cut] => 0
462+
[handle] => %i
463+
[refCount] => 0
464+
[position] => 1
465+
[attr] => Array
466+
(
467+
)
468+
469+
)
470+
471+
)
472+
473+
[1] => Array
474+
(
475+
[p1] => 123
476+
[p2] => Symfony\Component\VarDumper\Cloner\Stub Object
477+
(
478+
[type] => 4
479+
[class] => stdClass
480+
[value] =>
481+
[cut] => 0
482+
[handle] => %i
483+
[refCount] => 0
484+
[position] => 0
485+
[attr] => Array
486+
(
487+
)
488+
489+
)
490+
491+
)
492+
493+
)
494+
495+
[position:Symfony\Component\VarDumper\Cloner\Data:private] => 0
496+
[key:Symfony\Component\VarDumper\Cloner\Data:private] => 0
497+
[maxDepth:Symfony\Component\VarDumper\Cloner\Data:private] => 20
498+
[maxItemsPerDepth:Symfony\Component\VarDumper\Cloner\Data:private] => -1
499+
[useRefHandles:Symfony\Component\VarDumper\Cloner\Data:private] => -1
500+
)
501+
434502
EOTXT;
435503
$this->assertStringMatchesFormat($expected, print_r($clone, true));
436504
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
namespace Symfony\Component\VarDumper\Tests\Fixtures;
4+
5+
class Php74
6+
{
7+
public $p1 = 123;
8+
public \stdClass $p2;
9+
10+
public function __construct()
11+
{
12+
$this->p2 = new \stdClass();
13+
}
14+
}

0 commit comments

Comments
 (0)