From 0cde115b7fbbe2997f75d991be19de7f142000be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CFilip?= Date: Tue, 11 Jan 2022 13:16:26 +0100 Subject: [PATCH 1/2] [PropertyAccess] Fix handling of uninitialized property of anonymous class --- .../PropertyAccess/PropertyAccessor.php | 6 ++-- .../Tests/PropertyAccessorTest.php | 35 +++++++++++++++++++ 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php index 5d9298df7a52d..27b7e5197aff0 100644 --- a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php +++ b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php @@ -482,11 +482,11 @@ private function readProperty(array $zval, string $property, bool $ignoreInvalid } } catch (\Error $e) { // handle uninitialized properties in PHP >= 7.4 - if (\PHP_VERSION_ID >= 70400 && preg_match('/^Typed property ([\w\\\]+)::\$(\w+) must not be accessed before initialization$/', $e->getMessage(), $matches)) { - $r = new \ReflectionProperty($matches[1], $matches[2]); + if (\PHP_VERSION_ID >= 70400 && preg_match('/^Typed property [\w@\\\]+::\$(\w+) must not be accessed before initialization$/', $e->getMessage(), $matches)) { + $r = new \ReflectionProperty($class, $matches[1]); $type = ($type = $r->getType()) instanceof \ReflectionNamedType ? $type->getName() : (string) $type; - throw new UninitializedPropertyException(sprintf('The property "%s::$%s" is not readable because it is typed "%s". You should initialize it or declare a default value instead.', $r->getDeclaringClass()->getName(), $r->getName(), $type), 0, $e); + throw new UninitializedPropertyException(sprintf('The property "%s::$%s" is not readable because it is typed "%s". You should initialize it or declare a default value instead.', !str_contains(\get_class($object), "@anonymous\0") ? \get_class($object) : (get_parent_class($object) ?: key(class_implements($object)) ?: 'class').'@anonymous', $r->getName(), $type), 0, $e); } throw $e; diff --git a/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php index 521218f671c75..5368c9670947d 100644 --- a/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php +++ b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php @@ -206,6 +206,41 @@ public function getUninitialized(): array $this->propertyAccessor->getValue($object, 'uninitialized'); } + /** + * @requires PHP 7.4 + */ + public function testGetValueThrowsExceptionIfUninitializedNotNullablePropertyWithGetterOfAnonymousClass() + { + $this->expectException(UninitializedPropertyException::class); + $this->expectExceptionMessage('The property "class@anonymous::$uninitialized" is not readable because it is typed "string". You should initialize it or declare a default value instead.'); + + $object = eval('return new class() { + private string $uninitialized; + + public function getUninitialized(): string + { + return $this->uninitialized; + } + };'); + + $this->propertyAccessor->getValue($object, 'uninitialized'); + } + + /** + * @requires PHP 7.4 + */ + public function testGetValueThrowsExceptionIfUninitializedPropertyOfAnonymousClass() + { + $this->expectException(UninitializedPropertyException::class); + $this->expectExceptionMessage('The property "class@anonymous::$uninitialized" is not readable because it is typed "string". You should initialize it or declare a default value instead.'); + + $object = eval('return new class() { + public string $uninitialized; + };'); + + $this->propertyAccessor->getValue($object, 'uninitialized'); + } + public function testGetValueThrowsExceptionIfUninitializedPropertyWithGetterOfAnonymousStdClass() { $this->expectException(AccessException::class); From 8216b7e205b9a51c059031cc3713b3330e35fb0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CFilip?= Date: Tue, 11 Jan 2022 13:24:16 +0100 Subject: [PATCH 2/2] Fix wrong reference to declaring class --- src/Symfony/Component/PropertyAccess/PropertyAccessor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php index 27b7e5197aff0..b9ef294d70403 100644 --- a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php +++ b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php @@ -486,7 +486,7 @@ private function readProperty(array $zval, string $property, bool $ignoreInvalid $r = new \ReflectionProperty($class, $matches[1]); $type = ($type = $r->getType()) instanceof \ReflectionNamedType ? $type->getName() : (string) $type; - throw new UninitializedPropertyException(sprintf('The property "%s::$%s" is not readable because it is typed "%s". You should initialize it or declare a default value instead.', !str_contains(\get_class($object), "@anonymous\0") ? \get_class($object) : (get_parent_class($object) ?: key(class_implements($object)) ?: 'class').'@anonymous', $r->getName(), $type), 0, $e); + throw new UninitializedPropertyException(sprintf('The property "%s::$%s" is not readable because it is typed "%s". You should initialize it or declare a default value instead.', !str_contains(\get_class($object), "@anonymous\0") ? $r->getDeclaringClass()->getName() : (get_parent_class($object) ?: key(class_implements($object)) ?: 'class').'@anonymous', $r->getName(), $type), 0, $e); } throw $e;