10000 [PropertyAccess] Allow to disable magic __get & __set · jeremyFreeAgent/symfony@11b7bf3 · GitHub
[go: up one dir, main page]

Skip to content

Commit 11b7bf3

Browse files
committed
[PropertyAccess] Allow to disable magic __get & __set
1 parent 7e24fc1 commit 11b7bf3

22 files changed

+329
-45
lines changed

UPGRADE-5.2.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,17 @@ Mime
1717

1818
* Deprecated `Address::fromString()`, use `Address::create()` instead
1919

20+
PropertyAccess
21+
--------------
22+
23+
* Deprecated passing a boolean as the first argument of `PropertyAccessor::__construct()`.
24+
Pass a combination of bitwise flags instead.
25+
26+
PropertyInfo
27+
------------
28+
29+
* Dropped the `enable_magic_call_extraction` context option in `ReflectionExtractor::getWriteInfo()` and `ReflectionExtractor::getReadInfo()` in favor of `enable_magic_methods_extraction`.
30+
2031
TwigBundle
2132
----------
2233

UPGRADE-6.0.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,17 @@ PhpUnitBridge
108108

109109
* Removed support for `@expectedDeprecation` annotations, use the `ExpectDeprecationTrait::expectDeprecation()` method instead.
110110

111+
PropertyAccess
112+
--------------
113+
114+
* Dropped support of a boolean as the first argument of `PropertyAccessor::__construct()`.
115+
Pass a combination of bitwise flags instead.
116+
117+
PropertyInfo
118+
------------
119+
120+
* Dropped the `enable_magic_call_extraction` context option in `ReflectionExtractor::getWriteInfo()` and `ReflectionExtractor::getReadInfo()` in favor of `enable_magic_methods_extraction`.
121+
111122
Routing
112123
-------
113124

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -949,6 +949,8 @@ private function addPropertyAccessSection(ArrayNodeDefinition $rootNode)
949949
->info('Property access configuration')
950950
->children()
951951
->booleanNode('magic_call')->defaultFalse()->end()
952+
->booleanNode('magic_get')->defaultTrue()->end()
953+
->booleanNode('magic_set')->defaultTrue()->end()
952954
->booleanNode('throw_exception_on_invalid_index')->defaultFalse()->end()
953955
->booleanNode('throw_exception_on_invalid_property_path')->defaultTrue()->end()
954956
->end()

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1429,9 +1429,14 @@ private function registerPropertyAccessConfiguration(array $config, ContainerBui
14291429

14301430
$loader->load('property_access.php');
14311431

1432+
$magicMethods = PropertyAccessor::DISALLOW_MAGIC_METHODS;
1433+
$magicMethods |= $config['magic_call'] ? PropertyAccessor::MAGIC_CALL : 0;
1434+
$magicMethods |= $config['magic_get'] ? PropertyAccessor::MAGIC_GET : 0;
1435+
$magicMethods |= $config['magic_set'] ? PropertyAccessor::MAGIC_SET : 0;
1436+
14321437
$container
14331438
->getDefinition('property_accessor')
1434-
->replaceArgument(0, $config['magic_call'])
1439+
->replaceArgument(0, $magicMethods)
14351440
->replaceArgument(1, $config['throw_exception_on_invalid_index'])
14361441
->replaceArgument(3, $config['throw_exception_on_invalid_property_path'])
14371442
->replaceArgument(4, new Reference(PropertyReadInfoExtractorInterface::class, ContainerInterface::NULL_ON_INVALID_REFERENCE))

src/Symfony/Bundle/FrameworkBundle/Resources/config/property_access.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
$container->services()
1919
->set('property_accessor', PropertyAccessor::class)
2020
->args([
21-
abstract_arg('magicCall, set by the extension'),
21+
abstract_arg('magic methods allowed, set by the extension'),
2222
abstract_arg('throwExceptionOnInvalidIndex, set by the extension'),
2323
service('cache.property_access')->ignoreOnInvalid(),
2424
abstract_arg('throwExceptionOnInvalidPropertyPath, set by the extension'),

src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,8 @@
236236

237237
<xsd:complexType name="property_access">
238238
<xsd:attribute name="magic-call" type="xsd:boolean" />
239+
<xsd:attribute name="magic-get" type="xsd:boolean" />
240+
<xsd:attribute name="magic-set" type="xsd:boolean" />
239241
<xsd:attribute name="throw-exception-on-invalid-index" type="xsd:boolean" />
240242
<xsd:attribute name="throw-exception-on-invalid-property-path" type="xsd:boolean" />
241243
</xsd:complexType>

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,8 @@ protected static function getBundleDefaultConfig()
415415
],
416416
'property_access' => [
417417
'magic_call' => false,
418+
'magic_get' => true,
419+
'magic_set' => true,
418420
'throw_exception_on_invalid_index' => false,
419421
'throw_exception_on_invalid_property_path' => true,
420422
],

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/property_accessor.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
$container->loadFromExtension('framework', [
44
'property_access' => [
55
'magic_call' => true,
6+
'magic_get' => true,
7+
'magic_set' => false,
68
'throw_exception_on_invalid_index' => true,
79
'throw_exception_on_invalid_property_path' => false,
810
],

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/property_accessor.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@
77
http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
88

99
<framework:config>
10-
<framework:property-access magic-call="true" throw-exception-on-invalid-index="true" throw-exception-on-invalid-property-path="false"/>
10+
<framework:property-access magic-call="true" magic-get="true" magic-set="false" throw-exception-on-invalid-index="true" throw-exception-on-invalid-property-path="false"/>
1111
</framework:config>
1212
</container>
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
framework:
22
property_access:
33
magic_call: true
4+
magic_get: true
5+
magic_set: false
46
throw_exception_on_invalid_index: true
57
throw_exception_on_invalid_property_path: false

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ public function testPropertyAccessWithDefaultValue()
8686
$container = $this->createContainerFromFile('full');
8787

8888
$def = $container->getDefinition('property_accessor');
89-
$this->assertFalse($def->getArgument(0));
89+
$this->assertSame(PropertyAccessor::MAGIC_SET | PropertyAccessor::MAGIC_GET, $def->getArgument(0));
9090
$this->assertFalse($def->getArgument(1));
9191
$this->assertTrue($def->getArgument(3));
9292
}
@@ -95,7 +95,7 @@ public function testPropertyAccessWithOverriddenValues()
9595
{
9696
$container = $this->createContainerFromFile('property_accessor');
9797
$def = $container->getDefinition('property_accessor');
98-
$this->assertTrue($def->getArgument(0));
98+
$this->assertSame(PropertyAccessor::MAGIC_GET | PropertyAccessor::MAGIC_CALL, $def->getArgument(0));
9999
$this->assertTrue($def->getArgument(1));
100100
$this->assertFalse($def->getArgument(3));
101101
}

src/Symfony/Bundle/FrameworkBundle/composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@
8383
"symfony/messenger": "<4.4",
8484
"symfony/mime": "<4.4",
8585
"symfony/property-info": "<4.4",
86+
"symfony/property-access": "<5.2",
8687
"symfony/serializer": "<5.2",
8788
"symfony/stopwatch": "<4.4",
8889
"symfony/translation": "<5.0",

src/Symfony/Component/PropertyAccess/CHANGELOG.md

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

4+
5.2.0
5+
-----
6+
7+
* deprecated passing a boolean as the first argument of `PropertyAccessor::__construct()`, expecting a combination of bitwise flags instead
8+
* added the ability to disable usage of the magic `__get` & `__set` methods
9+
410
5.1.0
511
-----
612

src/Symfony/Component/PropertyAccess/PropertyAccessor.php

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,17 +38,23 @@
3838
*/
3939
class PropertyAccessor implements PropertyAccessorInterface
4040
{
41+
/** @var int Allow none of the magic methods */
42+
public const DISALLOW_MAGIC_METHODS = ReflectionExtractor::DISALLOW_MAGIC_METHODS;
43+
/** @var int Allow magic __get methods */
44+
public const MAGIC_GET = ReflectionExtractor::ALLOW_MAGIC_GET;
45+
/** @var int Allow magic __set methods */
46+
public const MAGIC_SET = ReflectionExtractor::ALLOW_MAGIC_SET;
47+
/** @var int Allow magic __call methods */
48+
public const MAGIC_CALL = ReflectionExtractor::ALLOW_MAGIC_CALL;
49+
4150
private const VALUE = 0;
4251
private const REF = 1;
4352
private const IS_REF_CHAINED = 2;
4453
private const CACHE_PREFIX_READ = 'r';
4554
private const CACHE_PREFIX_WRITE = 'w';
4655
private const CACHE_PREFIX_PROPERTY_PATH = 'p';
4756

48-
/**
49-
* @var bool
50-
*/
51-
private $magicCall;
57+
private $magicMethodsFlags;
5258
private $ignoreInvalidIndices;
5359
private $ignoreInvalidProperty;
5460

@@ -68,18 +74,27 @@ class PropertyAccessor implements PropertyAccessorInterface
6874
* @var PropertyWriteInfoExtractorInterface
6975
*/
7076
private $writeInfoExtractor;
71-
7277
private $readPropertyCache = [];
7378
private $writePropertyCache = [];
7479
private static $resultProto = [self::VALUE => null];
7580

7681
/**
7782
* Should not be used by application code. Use
7883
* {@link PropertyAccess::createPropertyAccessor()} instead.
84+
*
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
7988
*/
80-
public function __construct(bool $magicCall = false, bool $throwExceptionOnInvalidIndex = false, CacheItemPoolInterface $cacheItemPool = null, bool $throwExceptionOnInvalidPropertyPath = true, PropertyReadInfoExtractorInterface $readInfoExtractor = null, PropertyWriteInfoExtractorInterface $writeInfoExtractor = null)
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)
8190
{
82-
$this->magicCall = $magicCall;
91+
if (\is_bool($magicMethods)) {
92+
trigger_deprecation('symfony/property-info', '5.2', 'Passing a boolean to "%s()" first argument is deprecated since 5.1 and expect a combination of bitwise flags instead (i.e an integer).', __METHOD__);
93+
94+
$magicMethods = ($magicMethods ? self::MAGIC_CALL : 0) | self::MAGIC_GET | self::MAGIC_SET;
95+
}
96+
97+
$this->magicMethodsFlags = $magicMethods;
8398
$this->ignoreInvalidIndices = !$throwExceptionOnInvalidIndex;
8499
$this->cacheItemPool = $cacheItemPool instanceof NullAdapter ? null : $cacheItemPool; // Replace the NullAdapter by the null value
85100
$this->ignoreInvalidProperty = !$throwExceptionOnInvalidPropertyPath;
@@ -472,7 +487,7 @@ private function getReadInfo(string $class, string $property): ?PropertyReadInfo
472487

473488
$accessor = $this->readInfoExtractor->getReadInfo($class, $property, [
474489
'enable_getter_setter_extraction' => true,
475-
'enable_magic_call_extraction' => $this->magicCall,
490+
'enable_magic_methods_extraction' => $this->magicMethodsFlags,
476491
'enable_constructor_extraction' => false,
477492
]);
478493

@@ -592,7 +607,7 @@ private function getWriteInfo(string $class, string $property, $value): Property
592607

593608
$mutator = $this->writeInfoExtractor->getWriteInfo($class, $property, [
594609
'enable_getter_setter_extraction' => true,
595-
'enable_magic_call_extraction' => $this->magicCall,
610+
'enable_magic_methods_extraction' => $this->magicMethodsFlags,
596611
'enable_constructor_extraction' => false,
597612
'enable_adder_remover_extraction' => $useAdderAndRemover,
598613
]);

src/Symfony/Component/PropertyAccess/PropertyAccessorBuilder.php

Lines changed: 82 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222
*/
2323
class PropertyAccessorBuilder
2424
{
25-
private $magicCall = false;
25+
/** @var int */
26+
private $magicMethods = PropertyAccessor::MAGIC_GET | PropertyAccessor::MAGIC_SET;
2627
private $throwExceptionOnInvalidIndex = false;
2728
private $throwExceptionOnInvalidPropertyPath = true;
2829

@@ -41,14 +42,54 @@ class PropertyAccessorBuilder
4142
*/
4243
private $writeInfoExtractor;
4344

45+
/**
46+
* Enables the use of all magic methods by the PropertyAccessor.
47+
*/
48+
public function enableMagicMethods(): self
49+
{
50+
$this->magicMethods = PropertyAccessor::MAGIC_GET | PropertyAccessor::MAGIC_SET | PropertyAccessor::MAGIC_CALL;
51+
52+
return $this;
53+
}
54+
55+
/**
56+
* Disable the use of all magic methods by the PropertyAccessor.
57+
*/
58+
public function disableMagicMethods(): self
59+
{
60+
$this->magicMethods = PropertyAccessor::DISALLOW_MAGIC_METHODS;
61+
62+
return $this;
63+
}
64+
4465
/**
4566
* Enables the use of "__call" by the PropertyAccessor.
4667
*
4768
* @return $this
4869
*/
4970
public function enableMagicCall()
5071
{
51-
$this->magicCall = true;
72+
$this->magicMethods |= PropertyAccessor::MAGIC_CALL;
73+
74+
return $this;
75+
}
76+
77+
/**
78+
* Enables the use of "__get" by the PropertyAccessor.
79+
*/
80+
public function enableMagicGet(): self
81+
{
82+
$this->magicMethods |= PropertyAccessor::MAGIC_GET;
83+
84+
return $this;
85+
}
86+
87+
/**
88+
* Enables the use of "__set" by the PropertyAccessor.
89+
*/
90+
public function enableMagicSet(): self
91+
{
92+
$this->magicMethods |= PropertyAccessor::MAGIC_SET;
5293

5394
return $this;
5495
}
@@ -60,7 +101,27 @@ public function enableMagicCall()
60101
*/
61102
public function disableMagicCall()
62103
{
63-
$this->magicCall = false;
104+
$this->magicMethods ^= PropertyAccessor::MAGIC_CALL;
105+
106+
return $this;
107+
}
108+
109+
/**
110+
* Disables the use of "__get" by the PropertyAccessor.
111+
*/
112+
public function disableMagicGet(): self
113+
{
114+
$this->magicMethods ^= PropertyAccessor::MAGIC_GET;
115+
116+
return $this;
117+
}
118+
119+
/**
120+
* Disables the use of "__set" by the PropertyAccessor.
121+
*/
122+
public function disableMagicSet(): self
123+
{
124+
$this->magicMethods ^= PropertyAccessor::MAGIC_SET;
64125

65126
return $this;
66127
}
@@ -70,7 +131,23 @@ public function disableMagicCall()
70131
*/
71132
public function isMagicCallEnabled()
72133
{
73-
return $this->magicCall;
134+
return (bool) ($this->magicMethods & PropertyAccessor::MAGIC_CALL);
135+
}
136+
137+
/**
138+
* @return bool whether the use of "__get" by the PropertyAccessor is enabled
139+
*/
140+
public function isMagicGetEnabled(): bool
141+
{
142+
return $this->magicMethods & PropertyAccessor::MAGIC_GET;
143+
}
144+
145+
/**
146+
* @return bool whether the use of "__set" by the PropertyAccessor is enabled
147+
*/
148+
public function isMagicSetEnabled(): bool
149+
{
150+
return $this->magicMethods & PropertyAccessor::MAGIC_SET;
74151
}
75152

76153
/**
@@ -206,6 +283,6 @@ public function getWriteInfoExtractor(): ?PropertyWriteInfoExtractorInterface
206283
*/
207284
public function getPropertyAccessor()
208285
{
209-
return new PropertyAccessor($this->magicCall, $this->throwExceptionOnInvalidIndex, $this->cacheItemPool, $this->throwExceptionOnInvalidPropertyPath, $this->readInfoExtractor, $this->writeInfoExtractor);
286+
return new PropertyAccessor($this->magicMethods, $this->throwExceptionOnInvalidIndex, $this->cacheItemPool, $this->throwExceptionOnInvalidPropertyPath, $this->readInfoExtractor, $this->writeInfoExtractor);
210287
}
211288
}

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

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,21 @@ public function testDisableMagicCall()
4545
$this->assertSame($this->builder, $this->builder->disableMagicCall());
4646
}
4747

48-
public function testIsMagicCallEnable()
48+
public function testTogglingMagicGet()
49+
{
50+
$this->assertTrue($this->builder->isMagicGetEnabled());
51+
$this->assertFalse($this->builder->disableMagicGet()->isMagicCallEnabled());
52+
$this->assertTrue($this->builder->enableMagicGet()->isMagicGetEnabled());
53+
}
54+
55+
public function testTogglingMagicSet()
56+
{
57+
$this->assertTrue($this->builder->isMagicSetEnabled());
58+
$this->assertFalse($this->builder->disableMagicSet()->isMagicSetEnabled());
59+
$this->assertTrue($this->builder->enableMagicSet()->isMagicSetEnabled());
60+
}
61+
62+
public function testTogglingMagicCall()
4963
{
5064
$this->assertFalse($this->builder->isMagicCallEnabled());
5165
$this->assertTrue($this->builder->enableMagicCall()->isMagicCallEnabled());

0 commit comments

Comments
 (0)
0