[PropertyAccess] Fix TypeError parsing again.

This commit is contained in:
Alexander M. Turek 2020-05-29 02:02:01 +02:00
parent 03cad5a750
commit 03b4e98630
2 changed files with 61 additions and 2 deletions

View File

@ -479,9 +479,15 @@ class PropertyAccessor implements PropertyAccessorInterface
try {
$result[self::VALUE] = $object->{$access[self::ACCESS_NAME]}();
} catch (\TypeError $e) {
list($trace) = $e->getTrace();
// handle uninitialized properties in PHP >= 7
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)) {
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);
if (__FILE__ === $trace['file']
&& $access[self::ACCESS_NAME] === $trace['function']
&& $object instanceof $trace['class']
&& preg_match((sprintf('/Return value (?:of .*::\w+\(\) )?must be of (?:the )?type (\w+), null returned$/')), $e->getMessage(), $matches)
) {
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);
}
throw $e;

View File

@ -142,6 +142,59 @@ class PropertyAccessorTest extends TestCase
$this->propertyAccessor->getValue(new UninitializedPrivateProperty(), 'uninitialized');
}
/**
* @requires PHP 7
*/
public function testGetValueThrowsExceptionIfUninitializedPropertyWithGetterOfAnonymousClass()
{
$this->expectException('Symfony\Component\PropertyAccess\Exception\AccessException');
$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"?');
$object = eval('return new class() {
private $uninitialized;
public function getUninitialized(): array
{
return $this->uninitialized;
}
};');
$this->propertyAccessor->getValue($object, 'uninitialized');
}
/**
* @requires PHP 7
*/
public function testGetValueThrowsExceptionIfUninitializedPropertyWithGetterOfAnonymousStdClass()
{
$this->expectException('Symfony\Component\PropertyAccess\Exception\AccessException');
$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"?');
$object = eval('return new class() extends \stdClass {
private $uninitialized;
public function getUninitialized(): array
{
return $this->uninitialized;
}
};');
$this->propertyAccessor->getValue($object, 'uninitialized');
}
/**
* @requires PHP 7
*/
public function testGetValueThrowsExceptionIfUninitializedPropertyWithGetterOfAnonymousChildClass()
{
$this->expectException('Symfony\Component\PropertyAccess\Exception\AccessException');
$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"?');
$object = eval('return new class() extends \Symfony\Component\PropertyAccess\Tests\Fixtures\UninitializedPrivateProperty {};');
$this->propertyAccessor->getValue($object, 'uninitialized');
}
public function testGetValueThrowsExceptionIfNotArrayAccess()
{
$this->expectException('Symfony\Component\PropertyAccess\Exception\NoSuchIndexException');