bug #37622 [PropertyAccess] Fix accessing dynamic properties (andreyserdjuk)

This PR was submitted for the master branch but it was squashed and merged into the 5.1 branch instead.

Discussion
----------

[PropertyAccess] Fix accessing dynamic properties

| Q             | A
| ------------- | ---
| Branch?       | 5.1 (to be switched when merging)
| Bug fix?      | yes
| New feature?  | no <!-- please update src/**/CHANGELOG.md files -->
| Deprecations? | no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files -->
| Tickets       | Fix #37026 <!-- prefix each issue number with "Fix #", no need to create an issue if none exist, explain below instead -->
| License       | MIT
| Doc PR        | no <!-- required for new features -->
<!--
Replace this notice by a short README for your feature/bugfix. This will help people
understand your PR and can be used as a start for the documentation.

Additionally (see https://symfony.com/releases):
 - Always add tests and ensure they pass.
 - Never break backward compatibility (see https://symfony.com/bc).
 - Bug fixes must be submitted against the lowest maintained branch where they apply
   (lowest branches are regularly merged to upper ones so they get the fixes too.)
 - Features and deprecations must be submitted against branch master.
-->

Commits
-------

47bd0180d1 [PropertyAccess] Fix accessing dynamic properties
This commit is contained in:
Fabien Potencier 2020-08-26 15:25:49 +02:00
commit 92cb709222
3 changed files with 45 additions and 4 deletions

View File

@ -435,10 +435,16 @@ class PropertyAccessor implements PropertyAccessorInterface
throw $e;
}
} elseif ($object instanceof \stdClass && property_exists($object, $property)) {
$result[self::VALUE] = $object->$property;
if (isset($zval[self::REF])) {
$result[self::REF] = &$object->$property;
} elseif (property_exists($object, $property)) {
try {
$result[self::VALUE] = $object->$property;
if (isset($zval[self::REF])) {
$result[self::REF] = &$object->$property;
}
} catch (\Error $e) {
if (!$ignoreInvalidProperty) {
throw new NoSuchPropertyException(sprintf('Can\'t read protected or private property "%s" in class "%s".', $property, $class), 0, $e);
}
}
} elseif (!$ignoreInvalidProperty) {
throw new NoSuchPropertyException(sprintf('Can\'t get a way to read the property "%s" in class "%s".', $property, $class));

View File

@ -0,0 +1,11 @@
<?php
namespace Symfony\Component\PropertyAccess\Tests\Fixtures;
class TestClassDynamicProperty
{
public function __construct($dynamicProperty)
{
$this->dynamicProperty = $dynamicProperty;
}
}

View File

@ -21,6 +21,7 @@ use Symfony\Component\PropertyAccess\Tests\Fixtures\ReturnTyped;
use Symfony\Component\PropertyAccess\Tests\Fixtures\TestAdderRemoverInvalidArgumentLength;
use Symfony\Component\PropertyAccess\Tests\Fixtures\TestAdderRemoverInvalidMethods;
use Symfony\Component\PropertyAccess\Tests\Fixtures\TestClass;
use Symfony\Component\PropertyAccess\Tests\Fixtures\TestClassDynamicProperty;
use Symfony\Component\PropertyAccess\Tests\Fixtures\TestClassIsWritable;
use Symfony\Component\PropertyAccess\Tests\Fixtures\TestClassMagicCall;
use Symfony\Component\PropertyAccess\Tests\Fixtures\TestClassMagicGet;
@ -97,6 +98,29 @@ class PropertyAccessorTest extends TestCase
$this->assertSame($value, $this->propertyAccessor->getValue($objectOrArray, $path));
}
/**
* Test get dynamic value from object is other than \stdClass instance.
*/
public function testGetDynamicValue()
{
$value = 'dynamicPropertyValue';
$path = 'dynamicProperty';
$object = new TestClassDynamicProperty($value);
$this->assertSame($value, $this->propertyAccessor->getValue($object, $path));
}
/**
* Ensure exact exception with message was thrown on access to non-public property.
*/
public function testGetInaccessibleProperty()
{
$this->expectException('Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException');
$this->expectExceptionMessage(sprintf('Can\'t read protected or private property "%s" in class "%s".', 'protectedProperty', TestClass::class));
$this->propertyAccessor->getValue(new TestClass('Bernhard'), 'protectedProperty');
}
/**
* @dataProvider getPathsWithMissingProperty
*/