Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitec9aab8

Browse files
bug#59884 [VarExporter] Fix support for asymmetric visibility (nicolas-grekas)
This PR was merged into the 6.4 branch.Discussion----------[VarExporter] Fix support for asymmetric visibility| Q | A| ------------- | ---| Branch? | 6.4| Bug fix? | yes| New feature? | no| Deprecations? | no| Issues |Fix#59843| License | MITCommits-------7321bbf [VarExporter] Fix support for asymmetric visibility
2 parents5d6c29a +7321bbf commitec9aab8

File tree

10 files changed

+109
-51
lines changed

10 files changed

+109
-51
lines changed

‎src/Symfony/Component/VarExporter/Hydrator.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@ public static function hydrate(object $instance, array $properties = [], array $
6161
$propertyScopes = InternalHydrator::$propertyScopes[$class] ??= InternalHydrator::getPropertyScopes($class);
6262

6363
foreach ($propertiesas$name => &$value) {
64-
[$scope,$name,$readonlyScope] =$propertyScopes[$name] ?? [$class,$name,$class];
65-
$scopedProperties[$readonlyScope ??$scope][$name] = &$value;
64+
[$scope,$name,$writeScope] =$propertyScopes[$name] ?? [$class,$name,$class];
65+
$scopedProperties[$writeScope ??$scope][$name] = &$value;
6666
}
6767
unset($value);
6868
}

‎src/Symfony/Component/VarExporter/Internal/Exporter.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,8 @@ public static function prepare($values, $objectsPool, &$refsPool, &$objectsCount
9090
$properties =$serializeProperties;
9191
}else {
9292
foreach ($serializePropertiesas$n =>$v) {
93-
$c =$reflector->hasProperty($n) && ($p =$reflector->getProperty($n))->isReadOnly() ?$p->class :'stdClass';
93+
$p =$reflector->hasProperty($n) ?$reflector->getProperty($n) :null;
94+
$c =$p && (\PHP_VERSION_ID >=80400 ?$p->isProtectedSet() ||$p->isPrivateSet() :$p->isReadOnly()) ?$p->class :'stdClass';
9495
$properties[$c][$n] =$v;
9596
}
9697
}

‎src/Symfony/Component/VarExporter/Internal/Hydrator.php

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -271,19 +271,19 @@ public static function getPropertyScopes($class)
271271
$name =$property->name;
272272

273273
if (\ReflectionProperty::IS_PRIVATE &$flags) {
274-
$readonlyScope =null;
275-
if ($flags & \ReflectionProperty::IS_READONLY) {
276-
$readonlyScope =$class;
274+
$writeScope =null;
275+
if (\PHP_VERSION_ID >=80400 ?$property->isPrivateSet() : ($flags & \ReflectionProperty::IS_READONLY)) {
276+
$writeScope =$class;
277277
}
278-
$propertyScopes["\0$class\0$name"] =$propertyScopes[$name] = [$class,$name,$readonlyScope,$property];
278+
$propertyScopes["\0$class\0$name"] =$propertyScopes[$name] = [$class,$name,$writeScope,$property];
279279

280280
continue;
281281
}
282-
$readonlyScope =null;
283-
if ($flags & \ReflectionProperty::IS_READONLY) {
284-
$readonlyScope =$property->class;
282+
$writeScope =null;
283+
if (\PHP_VERSION_ID >=80400 ?$property->isProtectedSet() ||$property->isPrivateSet() : ($flags & \ReflectionProperty::IS_READONLY)) {
284+
$writeScope =$property->class;
285285
}
286-
$propertyScopes[$name] = [$class,$name,$readonlyScope,$property];
286+
$propertyScopes[$name] = [$class,$name,$writeScope,$property];
287287

288288
if (\ReflectionProperty::IS_PROTECTED &$flags) {
289289
$propertyScopes["\0*\0$name"] =$propertyScopes[$name];
@@ -298,9 +298,13 @@ public static function getPropertyScopes($class)
298298
foreach ($r->getProperties(\ReflectionProperty::IS_PRIVATE)as$property) {
299299
if (!$property->isStatic()) {
300300
$name =$property->name;
301-
$readonlyScope =$property->isReadOnly() ?$class :null;
302-
$propertyScopes["\0$class\0$name"] = [$class,$name,$readonlyScope,$property];
303-
$propertyScopes[$name] ??= [$class,$name,$readonlyScope,$property];
301+
if (\PHP_VERSION_ID <80400) {
302+
$writeScope =$property->isReadOnly() ?$class :null;
303+
}else {
304+
$writeScope =$property->isPrivateSet() ?$class :null;
305+
}
306+
$propertyScopes["\0$class\0$name"] = [$class,$name,$writeScope,$property];
307+
$propertyScopes[$name] ??= [$class,$name,$writeScope,$property];
304308
}
305309
}
306310
}

‎src/Symfony/Component/VarExporter/Internal/LazyObjectRegistry.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public static function getClassResetters($class)
5858
$propertyScopes = Hydrator::$propertyScopes[$class] ??= Hydrator::getPropertyScopes($class);
5959
}
6060

61-
foreach ($propertyScopesas$key => [$scope,$name,$readonlyScope]) {
61+
foreach ($propertyScopesas$key => [$scope,$name,$writeScope]) {
6262
$propertyScopes[$k ="\0$scope\0$name"] ??$propertyScopes[$k ="\0*\0$name"] ??$k =$name;
6363

6464
if ($k !==$key ||"\0$class\0lazyObjectState" ===$k) {
@@ -68,7 +68,7 @@ public static function getClassResetters($class)
6868
if ($k ===$name && ($propertyScopes[$k][4] ??false)) {
6969
$hookedProperties[$k] =true;
7070
}else {
71-
$classProperties[$readonlyScope ??$scope][$name] =$key;
71+
$classProperties[$writeScope ??$scope][$name] =$key;
7272
}
7373
}
7474

@@ -138,17 +138,17 @@ public static function getParentMethods($class)
138138
return$methods;
139139
}
140140

141-
publicstaticfunctiongetScope($propertyScopes,$class,$property,$readonlyScope =null)
141+
publicstaticfunctiongetScope($propertyScopes,$class,$property,$writeScope =null)
142142
{
143-
if (null ===$readonlyScope && !isset($propertyScopes[$k ="\0$class\0$property"]) && !isset($propertyScopes[$k ="\0*\0$property"])) {
143+
if (null ===$writeScope && !isset($propertyScopes[$k ="\0$class\0$property"]) && !isset($propertyScopes[$k ="\0*\0$property"])) {
144144
returnnull;
145145
}
146146
$frame =debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT | \DEBUG_BACKTRACE_IGNORE_ARGS,3)[2];
147147

148148
if (\ReflectionProperty::class ===$scope =$frame['class'] ?? \Closure::class) {
149149
$scope =$frame['object']->class;
150150
}
151-
if (null ===$readonlyScope &&'*' ===$k[1] && ($class ===$scope || (is_subclass_of($class,$scope) && !isset($propertyScopes["\0$scope\0$property"])))) {
151+
if (null ===$writeScope &&'*' ===$k[1] && ($class ===$scope || (is_subclass_of($class,$scope) && !isset($propertyScopes["\0$scope\0$property"])))) {
152152
returnnull;
153153
}
154154

‎src/Symfony/Component/VarExporter/Internal/LazyObjectState.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,8 @@ public function initialize($instance, $propertyName, $propertyScope)
7171
}
7272
$properties = (array)$instance;
7373
foreach ($valuesas$key =>$value) {
74-
if (!\array_key_exists($key,$properties) && [$scope,$name,$readonlyScope] =$propertyScopes[$key] ??null) {
75-
$scope =$readonlyScope ?? ('*' !==$scope ?$scope :$class);
74+
if (!\array_key_exists($key,$properties) && [$scope,$name,$writeScope] =$propertyScopes[$key] ??null) {
75+
$scope =$writeScope ?? ('*' !==$scope ?$scope :$class);
7676
$accessor = LazyObjectRegistry::$classAccessors[$scope] ??= LazyObjectRegistry::getClassAccessors($scope);
7777
$accessor['set']($instance,$name,$value);
7878

@@ -116,10 +116,10 @@ public function reset($instance): void
116116
$properties = (array)$instance;
117117
$onlyProperties =\is_array($this->initializer) ?$this->initializer :null;
118118

119-
foreach ($propertyScopesas$key => [$scope,$name,$readonlyScope]) {
119+
foreach ($propertyScopesas$key => [$scope,$name,$writeScope]) {
120120
$propertyScopes[$k ="\0$scope\0$name"] ??$propertyScopes[$k ="\0*\0$name"] ??$k =$name;
121121

122-
if ($k ===$key && (null !==$readonlyScope || !\array_key_exists($k,$properties))) {
122+
if ($k ===$key && (null !==$writeScope || !\array_key_exists($k,$properties))) {
123123
$skippedProperties[$k] =true;
124124
}
125125
}

‎src/Symfony/Component/VarExporter/LazyGhostTrait.php

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -113,10 +113,10 @@ public function initializeLazyObject(): static
113113
$properties = (array)$this;
114114
$propertyScopes = Hydrator::$propertyScopes[$class] ??= Hydrator::getPropertyScopes($class);
115115
foreach ($state->initializeras$key =>$initializer) {
116-
if (\array_key_exists($key,$properties) || ![$scope,$name,$readonlyScope] =$propertyScopes[$key] ??null) {
116+
if (\array_key_exists($key,$properties) || ![$scope,$name,$writeScope] =$propertyScopes[$key] ??null) {
117117
continue;
118118
}
119-
$scope =$readonlyScope ?? ('*' !==$scope ?$scope :$class);
119+
$scope =$writeScope ?? ('*' !==$scope ?$scope :$class);
120120

121121
if (null ===$values) {
122122
if (!\is_array($values = ($state->initializer["\0"])($this, Registry::$defaultProperties[$class]))) {
@@ -161,7 +161,7 @@ public function &__get($name): mixed
161161
$propertyScopes = Hydrator::$propertyScopes[$this::class] ??= Hydrator::getPropertyScopes($this::class);
162162
$scope =null;
163163

164-
if ([$class, ,$readonlyScope] =$propertyScopes[$name] ??null) {
164+
if ([$class, ,$writeScope] =$propertyScopes[$name] ??null) {
165165
$scope = Registry::getScope($propertyScopes,$class,$name);
166166
$state =$this->lazyObjectState ??null;
167167

@@ -175,7 +175,7 @@ public function &__get($name): mixed
175175
$property =null;
176176
}
177177

178-
if ($property?->isInitialized($this) ?? LazyObjectState::STATUS_UNINITIALIZED_PARTIAL !==$state->initialize($this,$name,$readonlyScope ??$scope)) {
178+
if ($property?->isInitialized($this) ?? LazyObjectState::STATUS_UNINITIALIZED_PARTIAL !==$state->initialize($this,$name,$writeScope ??$scope)) {
179179
goto get_in_scope;
180180
}
181181
}
@@ -199,7 +199,7 @@ public function &__get($name): mixed
199199

200200
try {
201201
if (null ===$scope) {
202-
if (null ===$readonlyScope) {
202+
if (null ===$writeScope) {
203203
return$this->$name;
204204
}
205205
$value =$this->$name;
@@ -208,7 +208,7 @@ public function &__get($name): mixed
208208
}
209209
$accessor = Registry::$classAccessors[$scope] ??= Registry::getClassAccessors($scope);
210210

211-
return$accessor['get']($this,$name,null !==$readonlyScope);
211+
return$accessor['get']($this,$name,null !==$writeScope);
212212
}catch (\Error$e) {
213213
if (\Error::class !==$e::class || !str_starts_with($e->getMessage(),'Cannot access uninitialized non-nullable property')) {
214214
throw$e;
@@ -223,7 +223,7 @@ public function &__get($name): mixed
223223

224224
$accessor['set']($this,$name, []);
225225

226-
return$accessor['get']($this,$name,null !==$readonlyScope);
226+
return$accessor['get']($this,$name,null !==$writeScope);
227227
}catch (\Error) {
228228
if (preg_match('/^Cannot access uninitialized non-nullable property ([^ ]++) by reference$/',$e->getMessage(),$matches)) {
229229
thrownew \Error('Typed property'.$matches[1].' must not be accessed before initialization',$e->getCode(),$e->getPrevious());
@@ -239,15 +239,15 @@ public function __set($name, $value): void
239239
$propertyScopes = Hydrator::$propertyScopes[$this::class] ??= Hydrator::getPropertyScopes($this::class);
240240
$scope =null;
241241

242-
if ([$class, ,$readonlyScope] =$propertyScopes[$name] ??null) {
243-
$scope = Registry::getScope($propertyScopes,$class,$name,$readonlyScope);
242+
if ([$class, ,$writeScope] =$propertyScopes[$name] ??null) {
243+
$scope = Registry::getScope($propertyScopes,$class,$name,$writeScope);
244244
$state =$this->lazyObjectState ??null;
245245

246-
if ($state && ($readonlyScope ===$scope ||isset($propertyScopes["\0$scope\0$name"]))
246+
if ($state && ($writeScope ===$scope ||isset($propertyScopes["\0$scope\0$name"]))
247247
&& LazyObjectState::STATUS_INITIALIZED_FULL !==$state->status
248248
) {
249249
if (LazyObjectState::STATUS_UNINITIALIZED_FULL ===$state->status) {
250-
$state->initialize($this,$name,$readonlyScope ??$scope);
250+
$state->initialize($this,$name,$writeScope ??$scope);
251251
}
252252
goto set_in_scope;
253253
}
@@ -274,13 +274,13 @@ public function __isset($name): bool
274274
$propertyScopes = Hydrator::$propertyScopes[$this::class] ??= Hydrator::getPropertyScopes($this::class);
275275
$scope =null;
276276

277-
if ([$class, ,$readonlyScope] =$propertyScopes[$name] ??null) {
277+
if ([$class, ,$writeScope] =$propertyScopes[$name] ??null) {
278278
$scope = Registry::getScope($propertyScopes,$class,$name);
279279
$state =$this->lazyObjectState ??null;
280280

281281
if ($state && (null ===$scope ||isset($propertyScopes["\0$scope\0$name"]))
282282
&& LazyObjectState::STATUS_INITIALIZED_FULL !==$state->status
283-
&& LazyObjectState::STATUS_UNINITIALIZED_PARTIAL !==$state->initialize($this,$name,$readonlyScope ??$scope)
283+
&& LazyObjectState::STATUS_UNINITIALIZED_PARTIAL !==$state->initialize($this,$name,$writeScope ??$scope)
284284
) {
285285
goto isset_in_scope;
286286
}
@@ -305,15 +305,15 @@ public function __unset($name): void
305305
$propertyScopes = Hydrator::$propertyScopes[$this::class] ??= Hydrator::getPropertyScopes($this::class);
306306
$scope =null;
307307

308-
if ([$class, ,$readonlyScope] =$propertyScopes[$name] ??null) {
309-
$scope = Registry::getScope($propertyScopes,$class,$name,$readonlyScope);
308+
if ([$class, ,$writeScope] =$propertyScopes[$name] ??null) {
309+
$scope = Registry::getScope($propertyScopes,$class,$name,$writeScope);
310310
$state =$this->lazyObjectState ??null;
311311

312-
if ($state && ($readonlyScope ===$scope ||isset($propertyScopes["\0$scope\0$name"]))
312+
if ($state && ($writeScope ===$scope ||isset($propertyScopes["\0$scope\0$name"]))
313313
&& LazyObjectState::STATUS_INITIALIZED_FULL !==$state->status
314314
) {
315315
if (LazyObjectState::STATUS_UNINITIALIZED_FULL ===$state->status) {
316-
$state->initialize($this,$name,$readonlyScope ??$scope);
316+
$state->initialize($this,$name,$writeScope ??$scope);
317317
}
318318
goto unset_in_scope;
319319
}

‎src/Symfony/Component/VarExporter/LazyProxyTrait.php

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ public function &__get($name): mixed
8989
$scope =null;
9090
$instance =$this;
9191

92-
if ([$class, ,$readonlyScope] =$propertyScopes[$name] ??null) {
92+
if ([$class, ,$writeScope] =$propertyScopes[$name] ??null) {
9393
$scope = Registry::getScope($propertyScopes,$class,$name);
9494

9595
if (null ===$scope ||isset($propertyScopes["\0$scope\0$name"])) {
@@ -122,7 +122,7 @@ public function &__get($name): mixed
122122

123123
try {
124124
if (null ===$scope) {
125-
if (null ===$readonlyScope &&1 !==$parent) {
125+
if (null ===$writeScope &&1 !==$parent) {
126126
return$instance->$name;
127127
}
128128
$value =$instance->$name;
@@ -131,7 +131,7 @@ public function &__get($name): mixed
131131
}
132132
$accessor = Registry::$classAccessors[$scope] ??= Registry::getClassAccessors($scope);
133133

134-
return$accessor['get']($instance,$name,null !==$readonlyScope ||1 ===$parent);
134+
return$accessor['get']($instance,$name,null !==$writeScope ||1 ===$parent);
135135
}catch (\Error$e) {
136136
if (\Error::class !==$e::class || !str_starts_with($e->getMessage(),'Cannot access uninitialized non-nullable property')) {
137137
throw$e;
@@ -146,7 +146,7 @@ public function &__get($name): mixed
146146

147147
$accessor['set']($instance,$name, []);
148148

149-
return$accessor['get']($instance,$name,null !==$readonlyScope ||1 ===$parent);
149+
return$accessor['get']($instance,$name,null !==$writeScope ||1 ===$parent);
150150
}catch (\Error) {
151151
throw$e;
152152
}
@@ -159,10 +159,10 @@ public function __set($name, $value): void
159159
$scope =null;
160160
$instance =$this;
161161

162-
if ([$class, ,$readonlyScope] =$propertyScopes[$name] ??null) {
163-
$scope = Registry::getScope($propertyScopes,$class,$name,$readonlyScope);
162+
if ([$class, ,$writeScope] =$propertyScopes[$name] ??null) {
163+
$scope = Registry::getScope($propertyScopes,$class,$name,$writeScope);
164164

165-
if ($readonlyScope ===$scope ||isset($propertyScopes["\0$scope\0$name"])) {
165+
if ($writeScope ===$scope ||isset($propertyScopes["\0$scope\0$name"])) {
166166
if ($state =$this->lazyObjectState ??null) {
167167
$instance =$state->realInstance ??= ($state->initializer)();
168168
}
@@ -227,10 +227,10 @@ public function __unset($name): void
227227
$scope =null;
228228
$instance =$this;
229229

230-
if ([$class, ,$readonlyScope] =$propertyScopes[$name] ??null) {
231-
$scope = Registry::getScope($propertyScopes,$class,$name,$readonlyScope);
230+
if ([$class, ,$writeScope] =$propertyScopes[$name] ??null) {
231+
$scope = Registry::getScope($propertyScopes,$class,$name,$writeScope);
232232

233-
if ($readonlyScope ===$scope ||isset($propertyScopes["\0$scope\0$name"])) {
233+
if ($writeScope ===$scope ||isset($propertyScopes["\0$scope\0$name"])) {
234234
if ($state =$this->lazyObjectState ??null) {
235235
$instance =$state->realInstance ??= ($state->initializer)();
236236
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespaceSymfony\Component\VarExporter\Tests\Fixtures\LazyProxy;
13+
14+
class AsymmetricVisibility
15+
{
16+
publicprivate(set)int$foo;
17+
18+
publicfunction__construct(int$foo)
19+
{
20+
$this->foo =$foo;
21+
}
22+
}

‎src/Symfony/Component/VarExporter/Tests/LazyGhostTraitTest.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
useSymfony\Component\VarExporter\Tests\Fixtures\LazyGhost\MagicClass;
2626
useSymfony\Component\VarExporter\Tests\Fixtures\LazyGhost\ReadOnlyClass;
2727
useSymfony\Component\VarExporter\Tests\Fixtures\LazyGhost\TestClass;
28+
useSymfony\Component\VarExporter\Tests\Fixtures\LazyProxy\AsymmetricVisibility;
2829
useSymfony\Component\VarExporter\Tests\Fixtures\LazyProxy\Hooked;
2930
useSymfony\Component\VarExporter\Tests\Fixtures\SimpleObject;
3031

@@ -504,6 +505,21 @@ public function testPropertyHooks()
504505
$this->assertSame(345,$object->backed);
505506
}
506507

508+
/**
509+
* @requires PHP 8.4
510+
*/
511+
publicfunctiontestAsymmetricVisibility()
512+
{
513+
$initialized =false;
514+
$object =$this->createLazyGhost(AsymmetricVisibility::class,function ($instance)use (&$initialized) {
515+
$initialized =true;
516+
517+
$instance->__construct(123);
518+
});
519+
520+
$this->assertSame(123,$object->foo);
521+
}
522+
507523
/**
508524
* @template T
509525
*

‎src/Symfony/Component/VarExporter/Tests/LazyProxyTraitTest.php

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818
useSymfony\Component\VarExporter\Exception\LogicException;
1919
useSymfony\Component\VarExporter\LazyProxyTrait;
2020
useSymfony\Component\VarExporter\ProxyHelper;
21-
useSymfony\Component\VarExporter\Tests\Fixtures\LazyGhost\RegularClass;
2221
useSymfony\Component\VarExporter\Tests\Fixtures\LazyProxy\AbstractHooked;
22+
useSymfony\Component\VarExporter\Tests\Fixtures\LazyProxy\AsymmetricVisibility;
2323
useSymfony\Component\VarExporter\Tests\Fixtures\LazyProxy\Hooked;
2424
useSymfony\Component\VarExporter\Tests\Fixtures\LazyProxy\FinalPublicClass;
2525
useSymfony\Component\VarExporter\Tests\Fixtures\LazyProxy\ReadOnlyClass;
@@ -364,6 +364,21 @@ public function testAbstractPropertyHooks()
364364
$this->assertTrue($initialized);
365365
}
366366

367+
/**
368+
* @requires PHP 8.4
369+
*/
370+
publicfunctiontestAsymmetricVisibility()
371+
{
372+
$initialized =false;
373+
$object =$this->createLazyProxy(AsymmetricVisibility::class,function ()use (&$initialized) {
374+
$initialized =true;
375+
376+
returnnewAsymmetricVisibility(123);
377+
});
378+
379+
$this->assertSame(123,$object->foo);
380+
}
381+
367382
/**
368383
* @template T
369384
*

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp