Skip to content

Navigation Menu

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

Appearance settings

Commit ec9aab8

Browse filesBrowse 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 | MIT Commits ------- 7321bbf [VarExporter] Fix support for asymmetric visibility
2 parents 5d6c29a + 7321bbf commit ec9aab8
Copy full SHA for ec9aab8

File tree

10 files changed

+109
-51
lines changed
Filter options

10 files changed

+109
-51
lines changed

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/VarExporter/Hydrator.php
+2-2Lines 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 ($properties as $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

Copy file name to clipboardExpand all lines: src/Symfony/Component/VarExporter/Internal/Exporter.php
+2-1Lines 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 ($serializeProperties as $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

Copy file name to clipboardExpand all lines: src/Symfony/Component/VarExporter/Internal/Hydrator.php
+15-11Lines 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

Copy file name to clipboardExpand all lines: src/Symfony/Component/VarExporter/Internal/LazyObjectRegistry.php
+5-5Lines 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 ($propertyScopes as $key => [$scope, $name, $readonlyScope]) {
61+
foreach ($propertyScopes as $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-
public static function getScope($propertyScopes, $class, $property, $readonlyScope = null)
141+
public static function getScope($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
return null;
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
return null;
153153
}
154154

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/VarExporter/Internal/LazyObjectState.php
+4-4Lines 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 ($values as $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 ($propertyScopes as $key => [$scope, $name, $readonlyScope]) {
119+
foreach ($propertyScopes as $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

Copy file name to clipboardExpand all lines: src/Symfony/Component/VarExporter/LazyGhostTrait.php
+17-17Lines 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->initializer as $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
throw new \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

Copy file name to clipboardExpand all lines: src/Symfony/Component/VarExporter/LazyProxyTrait.php
+10-10Lines 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
}
+22Lines 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+
namespace Symfony\Component\VarExporter\Tests\Fixtures\LazyProxy;
13+
14+
class AsymmetricVisibility
15+
{
16+
public private(set) int $foo;
17+
18+
public function __construct(int $foo)
19+
{
20+
$this->foo = $foo;
21+
}
22+
}

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/VarExporter/Tests/LazyGhostTraitTest.php
+16Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
use Symfony\Component\VarExporter\Tests\Fixtures\LazyGhost\MagicClass;
2626
use Symfony\Component\VarExporter\Tests\Fixtures\LazyGhost\ReadOnlyClass;
2727
use Symfony\Component\VarExporter\Tests\Fixtures\LazyGhost\TestClass;
28+
use Symfony\Component\VarExporter\Tests\Fixtures\LazyProxy\AsymmetricVisibility;
2829
use Symfony\Component\VarExporter\Tests\Fixtures\LazyProxy\Hooked;
2930
use Symfony\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+
public function testAsymmetricVisibility()
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

Copy file name to clipboardExpand all lines: src/Symfony/Component/VarExporter/Tests/LazyProxyTraitTest.php
+16-1Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818
use Symfony\Component\VarExporter\Exception\LogicException;
1919
use Symfony\Component\VarExporter\LazyProxyTrait;
2020
use Symfony\Component\VarExporter\ProxyHelper;
21-
use Symfony\Component\VarExporter\Tests\Fixtures\LazyGhost\RegularClass;
2221
use Symfony\Component\VarExporter\Tests\Fixtures\LazyProxy\AbstractHooked;
22+
use Symfony\Component\VarExporter\Tests\Fixtures\LazyProxy\AsymmetricVisibility;
2323
use Symfony\Component\VarExporter\Tests\Fixtures\LazyProxy\Hooked;
2424
use Symfony\Component\VarExporter\Tests\Fixtures\LazyProxy\FinalPublicClass;
2525
use Symfony\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+
public function testAsymmetricVisibility()
371+
{
372+
$initialized = false;
373+
$object = $this->createLazyProxy(AsymmetricVisibility::class, function () use (&$initialized) {
374+
$initialized = true;
375+
376+
return new AsymmetricVisibility(123);
377+
});
378+
379+
$this->assertSame(123, $object->foo);
380+
}
381+
367382
/**
368383
* @template T
369384
*

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.