8000 [PropertyAccess] Fix handling of uninitialized property of parent class · symfony/symfony@5cd10b0 · GitHub
[go: up one dir, main page]

Skip to content

Commit 5cd10b0

Browse files
filiplikavcannicolas-grekas
authored andcommitted
[PropertyAccess] Fix handling of uninitialized property of parent class
1 parent 9f5238d commit 5cd10b0

File tree

4 files changed

+54
-3
lines changed

4 files changed

+54
-3
lines changed

src/Symfony/Component/PropertyAccess/PropertyAccessor.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ private function readProperty(array $zval, string $property, bool $ignoreInvalid
401401
&& $object instanceof $trace['class']
402402
&& preg_match('/Return value (?:of .*::\w+\(\) )?must be of (?:the )?type (\w+), null returned$/', $e->getMessage(), $matches)
403403
) {
404-
throw new AccessException(sprintf('The method "%s::%s()" returned "null", but expected type "%3$s". Did you forget to initialize a property or to make the return type nullable using "?%3$s"?', !str_contains(\get_class($object), "@anonymous\0") ? \get_class($object) : (get_parent_class($object) ?: 'class').'@anonymous', $access[self::ACCESS_NAME], $matches[1]), 0, $e);
404+
throw new AccessException(sprintf('The method "%s::%s()" returned "null", but expected type "%3$s". Did you forget to initialize a property or to make the return type nullable using "?%3$s"?', get_debug_type($object), $access[self::ACCESS_NAME], $matches[1]), 0, $e);
405405
}
406406

407407
throw $e;
@@ -436,8 +436,8 @@ private function readProperty(array $zval, string $property, bool $ignoreInvalid
436436
}
437437
} catch (\Error $e) {
438438
// handle uninitialized properties in PHP >= 7.4
439-
if (\PHP_VERSION_ID >= 70400 && preg_match('/^Typed property ('.preg_quote(get_debug_type($object), '/').')::\$(\w+) must not be accessed before initialization$/', $e->getMessage(), $matches)) {
440-
$r = new \ReflectionProperty($class, $matches[2]);
439+
if (\PHP_VERSION_ID >= 70400 && preg_match('/^Typed property ([\w\\\\@]+)::\$(\w+) must not be accessed before initialization$/', $e->getMessage(), $matches)) {
440+
$r = new \ReflectionProperty(str_contains($matches[1], '@anonymous') ? $class : $matches[1], $matches[2]);
441441
$type = ($type = $r->getType()) instanceof \ReflectionNamedType ? $type->getName() : (string) $type;
442442

443443
throw new AccessException(sprintf('The property "%s::$%s" is not readable because it is typed "%s". You should initialize it or declare a default value instead.', $matches[1], $r->getName(), $type), 0, $e);
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
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\PropertyAccess\Tests\Fixtures;
13+
14+
class ExtendedUninitializedProperty extends UninitializedProperty
15+
{
16+
17+
}

src/Symfony/Component/PropertyAccess/Tests/Fixtures/UninitializedProperty.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,15 @@
1414
class UninitializedProperty
1515
{
1616
public string $uninitialized;
17+
private string $privateUninitialized;
18+
19+
public function getPrivateUninitialized(): string
20+
{
21+
return $this->privateUninitialized;
22+
}
23+
24+
public function setPrivateUninitialized(string $privateUninitialized): void
25+
{
26+
$this->privateUninitialized = $privateUninitialized;
27+
}
1728
}

src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException;
2121
use Symfony\Component\PropertyAccess\PropertyAccess;
2222
use Symfony\Component\PropertyAccess\PropertyAccessor;
23+
use Symfony\Component\PropertyAccess\Tests\Fixtures\ExtendedUninitializedProperty;
2324
use Symfony\Component\PropertyAccess\Tests\Fixtures\ReturnTyped;
2425
use Symfony\Component\PropertyAccess\Tests\Fixtures\TestAdderRemoverInvalidArgumentLength;
2526
use Symfony\Component\PropertyAccess\Tests\Fixtures\TestAdderRemoverInvalidMethods;
@@ -211,6 +212,28 @@ public function testGetValueThrowsExceptionIfUninitializedPropertyOfAnonymousCla
211212
$this->propertyAccessor->getValue($object, 'uninitialized');
212213
}
213214

215+
/**
216+
* @requires PHP 7.4
217+
*/
218+
public function testGetValueThrowsExceptionIfUninitializedNotNullableOfParentClass()
219+
{
220+
$this->expectException(AccessException::class);
221+
$this->expectExceptionMessage('The property "Symfony\Component\PropertyAccess\Tests\Fixtures\UninitializedProperty::$uninitialized" is not readable because it is typed "string". You should initialize it or declare a default value instead.');
222+
223+
$this->propertyAccessor->getValue(new ExtendedUninitializedProperty(), 'uninitialized');
224+
}
225+
226+
/**
227+
* @requires PHP 7.4
228+
*/
229+
public function testGetValueThrowsExceptionIfUninitializedNotNullablePropertyWithGetterOfParentClass()
230+
{
231+
$this->expectException(AccessException::class);
232+
$this->expectExceptionMessage('The property "Symfony\Component\PropertyAccess\Tests\Fixtures\UninitializedProperty::$privateUninitialized" is not readable because it is typed "string". You should initialize it or declare a default value instead.');
233+
234+
$this->propertyAccessor->getValue(new ExtendedUninitializedProperty(), 'privateUninitialized');
235+
}
236+
214237
public function testGetValueThrowsExceptionIfUninitializedPropertyWithGetterOfAnonymousStdClass()
215238
{
216239
$this->expectException(AccessException::class);

0 commit comments

Comments
 (0)
0