diff --git a/src/Symfony/Component/VarDumper/CHANGELOG.md b/src/Symfony/Component/VarDumper/CHANGELOG.md index 9329875010537..7481cff1a4cde 100644 --- a/src/Symfony/Component/VarDumper/CHANGELOG.md +++ b/src/Symfony/Component/VarDumper/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +6.4 +--- + + * Dump uninitialized properties + 6.3 --- diff --git a/src/Symfony/Component/VarDumper/Caster/Caster.php b/src/Symfony/Component/VarDumper/Caster/Caster.php index 32c69ee04dc43..e79ee735fb54b 100644 --- a/src/Symfony/Component/VarDumper/Caster/Caster.php +++ b/src/Symfony/Component/VarDumper/Caster/Caster.php @@ -32,6 +32,7 @@ class Caster public const EXCLUDE_EMPTY = 128; public const EXCLUDE_NOT_IMPORTANT = 256; public const EXCLUDE_STRICT = 512; + public const EXCLUDE_UNINITIALIZED = 1024; public const PREFIX_VIRTUAL = "\0~\0"; public const PREFIX_DYNAMIC = "\0+\0"; @@ -39,6 +40,8 @@ class Caster // usage: sprintf(Caster::PATTERN_PRIVATE, $class, $property) public const PATTERN_PRIVATE = "\0%s\0%s"; + private static array $classProperties = []; + /** * Casts objects to arrays and adds the dynamic property prefix. * @@ -61,20 +64,17 @@ public static function castObject(object $obj, string $class, bool $hasDebugInfo return $a; } + $classProperties = self::$classProperties[$class] ??= self::getClassProperties(new \ReflectionClass($class)); + $a = array_replace($classProperties, $a); + if ($a) { - static $publicProperties = []; $debugClass ??= get_debug_type($obj); $i = 0; $prefixedKeys = []; foreach ($a as $k => $v) { if ("\0" !== ($k[0] ?? '')) { - if (!isset($publicProperties[$class])) { - foreach ((new \ReflectionClass($class))->getProperties(\ReflectionProperty::IS_PUBLIC) as $prop) { - $publicProperties[$class][$prop->name] = true; - } - } - if (!isset($publicProperties[$class][$k])) { + if (!isset($classProperties[$k])) { $prefixedKeys[$i] = self::PREFIX_DYNAMIC.$k; } } elseif ($debugClass !== $class && 1 === strpos($k, $class)) { @@ -131,6 +131,8 @@ public static function filter(array $a, int $filter, array $listedProperties = [ $type |= self::EXCLUDE_EMPTY & $filter; } elseif (false === $v || '' === $v || '0' === $v || 0 === $v || 0.0 === $v || [] === $v) { $type |= self::EXCLUDE_EMPTY & $filter; + } elseif ($v instanceof UninitializedStub) { + $type |= self::EXCLUDE_UNINITIALIZED & $filter; } if ((self::EXCLUDE_NOT_IMPORTANT & $filter) && !\in_array($k, $listedProperties, true)) { $type |= self::EXCLUDE_NOT_IMPORTANT; @@ -169,4 +171,28 @@ public static function castPhpIncompleteClass(\__PHP_Incomplete_Class $c, array return $a; } + + private static function getClassProperties(\ReflectionClass $class): array + { + $classProperties = []; + $className = $class->name; + + foreach ($class->getProperties() as $p) { + if ($p->isStatic()) { + continue; + } + + $classProperties[match (true) { + $p->isPublic() => $p->name, + $p->isProtected() => self::PREFIX_PROTECTED.$p->name, + default => "\0".$className."\0".$p->name, + }] = new UninitializedStub($p); + } + + if ($parent = $class->getParentClass()) { + $classProperties += self::$classProperties[$parent->name] ??= self::getClassProperties($parent); + } + + return $classProperties; + } } diff --git a/src/Symfony/Component/VarDumper/Caster/UninitializedStub.php b/src/Symfony/Component/VarDumper/Caster/UninitializedStub.php new file mode 100644 index 0000000000000..a9bdd9b8130bf --- /dev/null +++ b/src/Symfony/Component/VarDumper/Caster/UninitializedStub.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +/** + * Represents an uninitialized property. + * + * @author Nicolas Grekas
+ */
+class UninitializedStub extends ConstStub
+{
+ public function __construct(\ReflectionProperty $property)
+ {
+ parent::__construct('?'.($property->hasType() ? ' '.$property->getType() : ''), 'Uninitialized property');
+ }
+}
diff --git a/src/Symfony/Component/VarDumper/Caster/XmlReaderCaster.php b/src/Symfony/Component/VarDumper/Caster/XmlReaderCaster.php
index d802bbf2a107f..1cfcf4dd8610e 100644
--- a/src/Symfony/Component/VarDumper/Caster/XmlReaderCaster.php
+++ b/src/Symfony/Component/VarDumper/Caster/XmlReaderCaster.php
@@ -85,6 +85,7 @@ public static function castXmlReader(\XMLReader $reader, array $a, Stub $stub, b
$info[$props]->cut = $count;
}
+ $a = Caster::filter($a, Caster::EXCLUDE_UNINITIALIZED, [], $count);
$info = Caster::filter($info, Caster::EXCLUDE_EMPTY, [], $count);
// +2 because hasValue and hasAttributes are always filtered
$stub->cut += $count + 2;
diff --git a/src/Symfony/Component/VarDumper/Tests/Caster/ExceptionCasterTest.php b/src/Symfony/Component/VarDumper/Tests/Caster/ExceptionCasterTest.php
index 66708944c63d6..f8fe43d8ddcee 100644
--- a/src/Symfony/Component/VarDumper/Tests/Caster/ExceptionCasterTest.php
+++ b/src/Symfony/Component/VarDumper/Tests/Caster/ExceptionCasterTest.php
@@ -378,6 +378,7 @@ public function testFlattenException()
-file: "%sExceptionCasterTest.php"
-line: %d
-asString: null
+ -dataRepresentation: ? Symfony\Component\VarDumper\Cloner\Data
}
]
EODUMP;
diff --git a/src/Symfony/Component/VarDumper/Tests/Caster/MysqliCasterTest.php b/src/Symfony/Component/VarDumper/Tests/Caster/MysqliCasterTest.php
index 983f541a3f786..4eba406efd325 100644
--- a/src/Symfony/Component/VarDumper/Tests/Caster/MysqliCasterTest.php
+++ b/src/Symfony/Component/VarDumper/Tests/Caster/MysqliCasterTest.php
@@ -30,7 +30,6 @@ public function testNotConnected()
$xCast = << 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:Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.