Skip to content

Commit 65ea38a

Browse files
[VarDumper] Dump uninitialized properties
1 parent deb160a commit 65ea38a

File tree

6 files changed

+65
-8
lines changed

6 files changed

+65
-8
lines changed

src/Symfony/Component/VarDumper/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
6.4
5+
---
6+
7+
* Dump uninitialized properties
8+
49
6.3
510
---
611

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

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,16 @@ class Caster
3232
public const EXCLUDE_EMPTY = 128;
3333
public const EXCLUDE_NOT_IMPORTANT = 256;
3434
public const EXCLUDE_STRICT = 512;
35+
public const EXCLUDE_UNINITIALIZED = 1024;
3536

3637
public const PREFIX_VIRTUAL = "\0~\0";
3738
public const PREFIX_DYNAMIC = "\0+\0";
3839
public const PREFIX_PROTECTED = "\0*\0";
3940
// usage: sprintf(Caster::PATTERN_PRIVATE, $class, $property)
4041
public const PATTERN_PRIVATE = "\0%s\0%s";
4142

43+
private static array $classProperties = [];
44+
4245
/**
4346
* Casts objects to arrays and adds the dynamic property prefix.
4447
*
@@ -61,20 +64,17 @@ public static function castObject(object $obj, string $class, bool $hasDebugInfo
6164
return $a;
6265
}
6366

67+
$classProperties = self::$classProperties[$class] ??= self::getClassProperties(new \ReflectionClass($class));
68+
$a = array_replace($classProperties, $a);
69+
6470
if ($a) {
65-
static $publicProperties = [];
6671
$debugClass ??= get_debug_type($obj);
6772

6873
$i = 0;
6974
$prefixedKeys = [];
7075
foreach ($a as $k => $v) {
7176
if ("\0" !== ($k[0] ?? '')) {
72-
if (!isset($publicProperties[$class])) {
73-
foreach ((new \ReflectionClass($class))->getProperties(\ReflectionProperty::IS_PUBLIC) as $prop) {
74-
$publicProperties[$class][$prop->name] = true;
75-
}
76-
}
77-
if (!isset($publicProperties[$class][$k])) {
77+
if (!isset($classProperties[$k])) {
7878
$prefixedKeys[$i] = self::PREFIX_DYNAMIC.$k;
7979
}
8080
} elseif ($debugClass !== $class && 1 === strpos($k, $class)) {
@@ -131,6 +131,8 @@ public static function filter(array $a, int $filter, array $listedProperties = [
131131
$type |= self::EXCLUDE_EMPTY & $filter;
132132
} elseif (false === $v || '' === $v || '0' === $v || 0 === $v || 0.0 === $v || [] === $v) {
133133
$type |= self::EXCLUDE_EMPTY & $filter;
134+
} elseif ($v instanceof UninitializedStub) {
135+
$type |= self::EXCLUDE_UNINITIALIZED & $filter;
134136
}
135137
if ((self::EXCLUDE_NOT_IMPORTANT & $filter) && !\in_array($k, $listedProperties, true)) {
136138
$type |= self::EXCLUDE_NOT_IMPORTANT;
@@ -169,4 +171,28 @@ public static function castPhpIncompleteClass(\__PHP_Incomplete_Class $c, array
169171

170172
return $a;
171173
}
174+
175+
private static function getClassProperties(\ReflectionClass $class): array
176+
{
177+
$classProperties = [];
178+
$className = $class->name;
179+
180+
foreach ($class->getProperties() as $p) {
181+
if ($p->isStatic()) {
182+
continue;
183+
}
184+
185+
$classProperties[match (true) {
186+
$p->isPublic() => $p->name,
187+
$p->isProtected() => self::PREFIX_PROTECTED.$p->name,
188+
default => "\0".$className."\0".$p->name,
189+
}] = new UninitializedStub($p);
190+
}
191+
192+
if ($parent = $class->getParentClass()) {
193+
$classProperties += self::$classProperties[$parent->name] ??= self::getClassProperties($parent);
194+
}
195+
196+
return $classProperties;
197+
}
172198
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\VarDumper\Caster;
13+
14+
/**
15+
* Represents an uninitialized property.
16+
*
17+
* @author Nicolas Grekas <p@tchwork.com>
18+
*/
19+
class UninitializedStub extends ConstStub
20+
{
21+
public function __construct(\ReflectionProperty $property)
22+
{
23+
parent::__construct('?'.($property->hasType() ? ' '.$property->getType() : ''), 'Uninitialized property');
24+
}
25+
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ public static function castXmlReader(\XMLReader $reader, array $a, Stub $stub, b
8585
$info[$props]->cut = $count;
8686
}
8787

88+
$a = Caster::filter($a, Caster::EXCLUDE_UNINITIALIZED, [], $count);
8889
$info = Caster::filter($info, Caster::EXCLUDE_EMPTY, [], $count);
8990
// +2 because hasValue and hasAttributes are always filtered
9091
$stub->cut += $count + 2;

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,7 @@ public function testFlattenException()
378378
-file: "%sExceptionCasterTest.php"
379379
-line: %d
380380
-asString: null
381+
-dataRepresentation: ? Symfony\Component\VarDumper\Cloner\Data
381382
}
382383
]
383384
EODUMP;

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ public function testNotConnected()
3030

3131
$xCast = <<<EODUMP
3232
mysqli_driver {%A
33-
+reconnect: false
3433
+report_mode: 3
3534
}
3635
EODUMP;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy