Skip to content

Commit fba0380

Browse files
committed
use bitwise flags to configure when the property accessor should throw
1 parent b34890a commit fba0380

File tree

6 files changed

+93
-16
lines changed

6 files changed

+93
-16
lines changed

UPGRADE-5.3.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@ PhpunitBridge
3333

3434
* Deprecated the `SetUpTearDownTrait` trait, use original methods with "void" return typehint.
3535

36+
PropertyAccess
37+
--------------
38+
39+
* Deprecated passing a boolean as the second argument of `PropertyAccessor::__construct()`.
40+
Pass a combination of bitwise flags instead.
41+
3642
PropertyInfo
3743
------------
3844

UPGRADE-6.0.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,8 @@ PhpUnitBridge
139139
PropertyAccess
140140
--------------
141141

142+
* Dropped support of a boolean as the second argument of `PropertyAccessor::__construct()`.
143+
Pass a combination of bitwise flags instead.
142144
* Dropped support of a boolean as the first argument of `PropertyAccessor::__construct()`.
143145
Pass a combination of bitwise flags instead.
144146

src/Symfony/Component/PropertyAccess/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
5.3.0
5+
-----
6+
7+
* deprecated passing a boolean as the second argument of `PropertyAccessor::__construct()`, expecting a combination of bitwise flags instead
8+
49
5.2.0
510
-----
611

src/Symfony/Component/PropertyAccess/PropertyAccessor.php

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ class PropertyAccessor implements PropertyAccessorInterface
4747
/** @var int Allow magic __call methods */
4848
public const MAGIC_CALL = ReflectionExtractor::ALLOW_MAGIC_CALL;
4949

50+
public const DO_NOT_THROW = 0;
51+
public const THROW_ON_INVALID_INDEX = 1;
52+
public const THROW_ON_INVALID_PROPERTY_PATH = 2;
53+
5054
private const VALUE = 0;
5155
private const REF = 1;
5256
private const IS_REF_CHAINED = 2;
@@ -82,22 +86,56 @@ class PropertyAccessor implements PropertyAccessorInterface
8286
* Should not be used by application code. Use
8387
* {@link PropertyAccess::createPropertyAccessor()} instead.
8488
*
85-
* @param int $magicMethods A bitwise combination of the MAGIC_* constants
86-
* to specify the allowed magic methods (__get, __set, __call)
87-
* or self::DISALLOW_MAGIC_METHODS for none
89+
* @param int $magicMethods A bitwise combination of the MAGIC_* constants
90+
* to specify the allowed magic methods (__get, __set, __call)
91+
* or self::DISALLOW_MAGIC_METHODS for none
92+
* @param int $throw A bitwise combination of the THROW_* constants
93+
* to specify when exceptions should be thrown
94+
* @param PropertyReadInfoExtractorInterface $readInfoExtractor
95+
* @param PropertyWriteInfoExtractorInterface $writeInfoExtractor
8896
*/
89-
public function __construct(/*int */$magicMethods = self::MAGIC_GET | self::MAGIC_SET, bool $throwExceptionOnInvalidIndex = false, CacheItemPoolInterface $cacheItemPool = null, bool $throwExceptionOnInvalidPropertyPath = true, PropertyReadInfoExtractorInterface $readInfoExtractor = null, PropertyWriteInfoExtractorInterface $writeInfoExtractor = null)
97+
public function __construct(/*int */$magicMethods = self::MAGIC_GET | self::MAGIC_SET, /*int */$throw = self::THROW_ON_INVALID_PROPERTY_PATH, CacheItemPoolInterface $cacheItemPool = null, /*PropertyReadInfoExtractorInterface */$readInfoExtractor = null, /*PropertyWriteInfoExtractorInterface */$writeInfoExtractor = null)
9098
{
9199
if (\is_bool($magicMethods)) {
92100
trigger_deprecation('symfony/property-access', '5.2', 'Passing a boolean as the first argument to "%s()" is deprecated. Pass a combination of bitwise flags instead (i.e an integer).', __METHOD__);
93101

94102
$magicMethods = ($magicMethods ? self::MAGIC_CALL : 0) | self::MAGIC_GET | self::MAGIC_SET;
95103
}
96104

105+
if (\is_bool($throw)) {
106+
trigger_deprecation('symfony/property-access', '5.3', 'Passing a boolean as the second argument to "%s()" is deprecated. Pass a combination of bitwise flags instead (i.e an integer).', __METHOD__);
107+
108+
$throw = $throw ? self::THROW_ON_INVALID_INDEX : self::DO_NOT_THROW;
109+
110+
if (!\is_bool($readInfoExtractor)) {
111+
$throw |= self::THROW_ON_INVALID_PROPERTY_PATH;
112+
}
113+
}
114+
115+
if (\is_bool($readInfoExtractor)) {
116+
trigger_deprecation('symfony/property-access', '5.3', 'Passing a boolean as the fourth argument to "%s()" is deprecated. Pass a %s instance instead.', __METHOD__, PropertyReadInfoExtractorInterface::class);
117+
118+
if ($readInfoExtractor) {
119+
$throw |= self::THROW_ON_INVALID_PROPERTY_PATH;
120+
}
121+
122+
$readInfoExtractor = $writeInfoExtractor;
123+
124+
if (null !== $readInfoExtractor && !$readInfoExtractor instanceof PropertyReadInfoExtractorInterface) {
125+
throw new \TypeError(sprintf('Argument 4 passed to "%s()" must be null or an instance of %s, "%s" given.', __METHOD__, PropertyReadInfoExtractorInterface::class, get_debug_type($readInfoExtractor)));
126+
}
127+
128+
$writeInfoExtractor = 4 < \func_num_args() ? func_get_arg(4) : null;
129+
130+
if (null !== $writeInfoExtractor && !$writeInfoExtractor instanceof PropertyWriteInfoExtractorInterface) {
131+
throw new \TypeError(sprintf('Argument 5 passed to "%s()" must be null or an instance of %s, "%s" given.', __METHOD__, PropertyWriteInfoExtractorInterface::class, get_debug_type($writeInfoExtractor)));
132+
}
133+
}
134+
97135
$this->magicMethodsFlags = $magicMethods;
98-
$this->ignoreInvalidIndices = !$throwExceptionOnInvalidIndex;
136+
$this->ignoreInvalidIndices = 0 === ($throw & self::THROW_ON_INVALID_INDEX);
99137
$this->cacheItemPool = $cacheItemPool instanceof NullAdapter ? null : $cacheItemPool; // Replace the NullAdapter by the null value
100-
$this->ignoreInvalidProperty = !$throwExceptionOnInvalidPropertyPath;
138+
$this->ignoreInvalidProperty = 0 === ($throw & self::THROW_ON_INVALID_PROPERTY_PATH);
101139
$this->readInfoExtractor = $readInfoExtractor ?? new ReflectionExtractor([], null, null, false);
102140
$this->writeInfoExtractor = $writeInfoExtractor ?? new ReflectionExtractor(['set'], null, null, false);
103141
}

src/Symfony/Component/PropertyAccess/PropertyAccessorBuilder.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,16 @@ public function getWriteInfoExtractor(): ?PropertyWriteInfoExtractorInterface
283283
*/
284284
public function getPropertyAccessor()
285285
{
286-
return new PropertyAccessor($this->magicMethods, $this->throwExceptionOnInvalidIndex, $this->cacheItemPool, $this->throwExceptionOnInvalidPropertyPath, $this->readInfoExtractor, $this->writeInfoExtractor);
286+
$throw = PropertyAccessor::DO_NOT_THROW;
287+
288+
if ($this->throwExceptionOnInvalidIndex) {
289+
$throw |= PropertyAccessor::THROW_ON_INVALID_INDEX;
290+
}
291+
292+
if ($this->throwExceptionOnInvalidPropertyPath) {
293+
$throw |= PropertyAccessor::THROW_ON_INVALID_PROPERTY_PATH;
294+
}
295+
296+
return new PropertyAccessor($this->magicMethods, $throw, $this->cacheItemPool, $this->readInfoExtractor, $this->writeInfoExtractor);
287297
}
288298
}

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

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\PropertyAccess\Tests;
1313

1414
use PHPUnit\Framework\TestCase;
15+
use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
1516
use Symfony\Component\Cache\Adapter\ArrayAdapter;
1617
use Symfony\Component\PropertyAccess\Exception\NoSuchIndexException;
1718
use Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException;
@@ -35,6 +36,8 @@
3536

3637
class PropertyAccessorTest extends TestCase
3738
{
39+
use ExpectDeprecationTrait;
40+
3841
/**
3942
* @var PropertyAccessor
4043
*/
@@ -131,6 +134,19 @@ public function testGetValueThrowsNoExceptionIfIndexNotFound($objectOrArray, $pa
131134
public function testGetValueThrowsExceptionIfIndexNotFoundAndIndexExceptionsEnabled($objectOrArray, $path)
132135
{
133136
$this->expectException('Symfony\Component\PropertyAccess\Exception\NoSuchIndexException');
137+
$this->propertyAccessor = new PropertyAccessor(PropertyAccessor::DISALLOW_MAGIC_METHODS, PropertyAccessor::THROW_ON_INVALID_INDEX | PropertyAccessor::THROW_ON_INVALID_PROPERTY_PATH);
138+
$this->propertyAccessor->getValue($objectOrArray, $path);
139+
}
140+
141+
/**
142+
* @group legacy
143+
* @dataProvider getPathsWithMissingIndex
144+
*/
145+
public function testGetValueThrowsExceptionIfIndexNotFoundAndIndexExceptionsEnabledUsingBooleanArgument($objectOrArray, $path)
146+
{
147+
$this->expectException('Symfony\Component\PropertyAccess\Exception\NoSuchIndexException');
148+
$this->expectDeprecation('Since symfony/property-access 5.3: Passing a boolean as the second argument to "Symfony\Component\PropertyAccess\PropertyAccessor::__construct()" is deprecated. Pass a combination of bitwise flags instead (i.e an integer).');
149+
134150
$this->propertyAccessor = new PropertyAccessor(PropertyAccessor::DISALLOW_MAGIC_METHODS, true);
135151
$this->propertyAccessor->getValue($objectOrArray, $path);
136152
}
@@ -253,7 +269,7 @@ public function testGetValueNotModifyObject()
253269

254270
public function testGetValueNotModifyObjectException()
255271
{
256-
$propertyAccessor = new PropertyAccessor(PropertyAccessor::DISALLOW_MAGIC_METHODS, true);
272+
$propertyAccessor = new PropertyAccessor(PropertyAccessor::DISALLOW_MAGIC_METHODS, PropertyAccessor::THROW_ON_INVALID_INDEX | PropertyAccessor::THROW_ON_INVALID_PROPERTY_PATH);
257273
$object = new \stdClass();
258274
$object->firstName = ['Bernhard'];
259275

@@ -341,7 +357,7 @@ public function testSetValueThrowsNoExceptionIfIndexNotFound($objectOrArray, $pa
341357
*/
342358
public function testSetValueThrowsNoExceptionIfIndexNotFoundAndIndexExceptionsEnabled($objectOrArray, $path)
343359
{
344-
$this->propertyAccessor = new PropertyAccessor(PropertyAccessor::DISALLOW_MAGIC_METHODS, true);
360+
$this->propertyAccessor = new PropertyAccessor(PropertyAccessor::DISALLOW_MAGIC_METHODS, PropertyAccessor::THROW_ON_INVALID_INDEX | PropertyAccessor::THROW_ON_INVALID_PROPERTY_PATH);
345361
$this->propertyAccessor->setValue($objectOrArray, $path, 'Updated');
346362

347363
$this->assertSame('Updated', $this->propertyAccessor->getValue($objectOrArray, $path));
@@ -428,7 +444,7 @@ public function testSetValueThrowsExceptionIfNotObjectOrArray($objectOrArray, $p
428444

429445
public function testGetValueWhenArrayValueIsNull()
430446
{
431-
$this->propertyAccessor = new PropertyAccessor(PropertyAccessor::DISALLOW_MAGIC_METHODS, true);
447+
$this->propertyAccessor = new PropertyAccessor(PropertyAccessor::DISALLOW_MAGIC_METHODS, PropertyAccessor::THROW_ON_INVALID_INDEX | PropertyAccessor::THROW_ON_INVALID_PROPERTY_PATH);
432448
$this->assertNull($this->propertyAccessor->getValue(['index' => ['nullable' => null]], '[index][nullable]'));
433449
}
434450

@@ -462,7 +478,7 @@ public function testIsReadableReturnsTrueIfIndexNotFound($objectOrArray, $path)
462478
*/
463479
public function testIsReadableReturnsFalseIfIndexNotFoundAndIndexExceptionsEnabled($objectOrArray, $path)
464480
{
465-
$this->propertyAccessor = new PropertyAccessor(PropertyAccessor::DISALLOW_MAGIC_METHODS, true);
481+
$this->propertyAccessor = new PropertyAccessor(PropertyAccessor::DISALLOW_MAGIC_METHODS, PropertyAccessor::THROW_ON_INVALID_INDEX | PropertyAccessor::THROW_ON_INVALID_PROPERTY_PATH);
466482

467483
// When exceptions are enabled, non-existing indices cannot be read
468484
$this->assertFalse($this->propertyAccessor->isReadable($objectOrArray, $path));
@@ -534,7 +550,7 @@ public function testIsWritableReturnsTrueIfIndexNotFound($objectOrArray, $path)
534550
*/
535551
public function testIsWritableReturnsTrueIfIndexNotFoundAndIndexExceptionsEnabled($objectOrArray, $path)
536552
{
537-
$this->propertyAccessor = new PropertyAccessor(PropertyAccessor::DISALLOW_MAGIC_METHODS, true);
553+
$this->propertyAccessor = new PropertyAccessor(PropertyAccessor::DISALLOW_MAGIC_METHODS, PropertyAccessor::THROW_ON_INVALID_INDEX | PropertyAccessor::THROW_ON_INVALID_PROPERTY_PATH);
538554

539555
// Non-existing indices can be written even if exceptions are enabled
540556
$this->assertTrue($this->propertyAccessor->isWritable($objectOrArray, $path));
@@ -718,7 +734,7 @@ public function testCacheReadAccess()
718734
{
719735
$obj = new TestClass('foo');
720736

721-
$propertyAccessor = new PropertyAccessor(PropertyAccessor::DISALLOW_MAGIC_METHODS, false, new ArrayAdapter());
737+
$propertyAccessor = new PropertyAccessor(PropertyAccessor::DISALLOW_MAGIC_METHODS, PropertyAccessor::THROW_ON_INVALID_PROPERTY_PATH, new ArrayAdapter());
722738
$this->assertEquals('foo', $propertyAccessor->getValue($obj, 'publicGetSetter'));
723739
$propertyAccessor->setValue($obj, 'publicGetSetter', 'bar');
724740
$propertyAccessor->setValue($obj, 'publicGetSetter', 'baz');
@@ -732,7 +748,7 @@ public function testAttributeWithSpecialChars()
732748
$obj->{'a/b'} = '1';
733749
$obj->{'a%2Fb'} = '2';
734750

735-
$propertyAccessor = new PropertyAccessor(PropertyAccessor::DISALLOW_MAGIC_METHODS, false, new ArrayAdapter());
751+
$propertyAccessor = new PropertyAccessor(PropertyAccessor::DISALLOW_MAGIC_METHODS, PropertyAccessor::THROW_ON_INVALID_PROPERTY_PATH, new ArrayAdapter());
736752
$this->assertSame('bar', $propertyAccessor->getValue($obj, '@foo'));
737753
$this->assertSame('1', $propertyAccessor->getValue($obj, 'a/b'));
738754
$this->assertSame('2', $propertyAccessor->getValue($obj, 'a%2Fb'));
@@ -753,7 +769,7 @@ public function testAnonymousClassRead()
753769

754770
$obj = $this->generateAnonymousClass($value);
755771

756-
$propertyAccessor = new PropertyAccessor(PropertyAccessor::DISALLOW_MAGIC_METHODS, false, new ArrayAdapter());
772+
$propertyAccessor = new PropertyAccessor(PropertyAccessor::DISALLOW_MAGIC_METHODS, PropertyAccessor::THROW_ON_INVALID_PROPERTY_PATH, new ArrayAdapter());
757773

758774
$this->assertEquals($value, $propertyAccessor->getValue($obj, 'foo'));
759775
}
@@ -781,7 +797,7 @@ public function testAnonymousClassWrite()
781797

782798
$obj = $this->generateAnonymousClass('');
783799

784-
$propertyAccessor = new PropertyAccessor(PropertyAccessor::DISALLOW_MAGIC_METHODS, false, new ArrayAdapter());
800+
$propertyAccessor = new PropertyAccessor(PropertyAccessor::DISALLOW_MAGIC_METHODS, PropertyAccessor::THROW_ON_INVALID_PROPERTY_PATH, new ArrayAdapter());
785801
$propertyAccessor->setValue($obj, 'foo', $value);
786802

787803
$this->assertEquals($value, $propertyAccessor->getValue($obj, 'foo'));

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy