Skip to content

Commit

Permalink
[PropertyAccess] Fix TypeError parsing again.
Browse files Browse the repository at this point in the history
  • Loading branch information
derrabus committed May 29, 2020
1 parent f609daf commit e1a6c91
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 2 deletions.
10 changes: 8 additions & 2 deletions PropertyAccessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -479,9 +479,15 @@ private function readProperty($zval, $property)
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;
Expand Down
53 changes: 53 additions & 0 deletions Tests/PropertyAccessorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,59 @@ public function testGetValueThrowsExceptionIfUninitializedPropertyWithGetter()
$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');
Expand Down

0 comments on commit e1a6c91

Please sign in to comment.