Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ca66e6c

Browse files
minor #37003 [PropertyAccess] Fix TypeError parsing again (derrabus)
This PR was merged into the 3.4 branch. Discussion ---------- [PropertyAccess] Fix TypeError parsing again | Q | A | ------------- | --- | Branch? | 3.4 | Bug fix? | yes | New feature? | no | Deprecations? | no | Tickets | #36872 | License | MIT | Doc PR | N/A Apparently, the format of `TypeError`s has changed again in php8. While investigating, I noticed our error message parsing is not handling anonymous classes well, so I've added some test cases for them. I chose a fuzzier regular expression to parse the expected return type from the error message. Additionally, I'm checking the stack trace if the caught `TypeError` is really caused by the accessor call. Commits ------- 03b4e98 [PropertyAccess] Fix TypeError parsing again.
2 parents 2e8ae40 + 03b4e98 commit ca66e6c

File tree

2 files changed

+61
-2
lines changed

2 files changed

+61
-2
lines changed

src/Symfony/Component/PropertyAccess/PropertyAccessor.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -479,9 +479,15 @@ private function readProperty($zval, $property)
479479
try {
480480
$result[self::VALUE] = $object->{$access[self::ACCESS_NAME]}();
481481
} catch (\TypeError $e) {
482+
list($trace) = $e->getTrace();
483+
482484
// handle uninitialized properties in PHP >= 7
483-
if (preg_match((sprintf('/^Return value of %s::%s\(\) must be of (?:the )?type (\w+), null returned$/', preg_quote(\get_class($object)), $access[self::ACCESS_NAME])), $e->getMessage(), $matches)) {
484-
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_class($object), $access[self::ACCESS_NAME], $matches[1]), 0, $e);
485+
if (__FILE__ === $trace['file']
486+
&& $access[self::ACCESS_NAME] === $trace['function']
487+
&& $object instanceof $trace['class']
488+
&& preg_match((sprintf('/Return value (?:of .*::\w+\(\) )?must be of (?:the )?type (\w+), null returned$/')), $e->getMessage(), $matches)
489+
) {
490+
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"?', false === strpos(\get_class($object), "@anonymous\0") ? \get_class($object) : (get_parent_class($object) ?: 'class').'@anonymous', $access[self::ACCESS_NAME], $matches[1]), 0, $e);
485491
}
486492

487493
throw $e;

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

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,59 @@ public function testGetValueThrowsExceptionIfUninitializedPropertyWithGetter()
142142
$this->propertyAccessor->getValue(new UninitializedPrivateProperty(), 'uninitialized');
143143
}
144144

145+
/**
146+
* @requires PHP 7
147+
*/
148+
public function testGetValueThrowsExceptionIfUninitializedPropertyWithGetterOfAnonymousClass()
149+
{
150+
$this->expectException('Symfony\Component\PropertyAccess\Exception\AccessException');
151+
$this->expectExceptionMessage('The method "class@anonymous::getUninitialized()" returned "null", but expected type "array". Did you forget to initialize a property or to make the return type nullable using "?array"?');
152+
153+
$object = eval('return new class() {
154+
private $uninitialized;
155+
156+
public function getUninitialized(): array
157+
{
158+
return $this->uninitialized;
159+
}
160+
};');
161+
162+
$this->propertyAccessor->getValue($object, 'uninitialized');
163+
}
164+
165+
/**
166+
* @requires PHP 7
167+
*/
168+
public function testGetValueThrowsExceptionIfUninitializedPropertyWithGetterOfAnonymousStdClass()
169+
{
170+
$this->expectException('Symfony\Component\PropertyAccess\Exception\AccessException');
171+
$this->expectExceptionMessage('The method "stdClass@anonymous::getUninitialized()" returned "null", but expected type "array". Did you forget to initialize a property or to make the return type nullable using "?array"?');
172+
173+
$object = eval('return new class() extends \stdClass {
174+
private $uninitialized;
175+
176+
public function getUninitialized(): array
177+
{
178+
return $this->uninitialized;
179+
}
180+
};');
181+
182+
$this->propertyAccessor->getValue($object, 'uninitialized');
183+
}
184+
185+
/**
186+
* @requires PHP 7
187+
*/
188+
public function testGetValueThrowsExceptionIfUninitializedPropertyWithGetterOfAnonymousChildClass()
189+
{
190+
$this->expectException('Symfony\Component\PropertyAccess\Exception\AccessException');
191+
$this->expectExceptionMessage('The method "Symfony\Component\PropertyAccess\Tests\Fixtures\UninitializedPrivateProperty@anonymous::getUninitialized()" returned "null", but expected type "array". Did you forget to initialize a property or to make the return type nullable using "?array"?');
192+
193+
$object = eval('return new class() extends \Symfony\Component\PropertyAccess\Tests\Fixtures\UninitializedPrivateProperty {};');
194+
195+
$this->propertyAccessor->getValue($object, 'uninitialized');
196+
}
197+
145198
public function testGetValueThrowsExceptionIfNotArrayAccess()
146199
{
147200
$this->expectException('Symfony\Component\PropertyAccess\Exception\NoSuchIndexException');

0 commit comments

Comments
 (0)