Skip to content

Commit d97726e

Browse files
Merge branch '6.4' into 7.0
* 6.4: [Translation] Improve tests coverage [Routing] Add redirection.io as sponsor of versions 6.4/7.0/7.1 don't check parameter values if they are not set [HttpClient] Add Innovative Web AG (i-web) as sponsor of version 6.4/7.0 [Serializer] Fix normalization relying on allowed attributes only Minor @var doc update [Translation] Remove `@internal` from abstract testcases [VarExporter] Work around php/php-src#12695 for lazy objects, fixing nullsafe-related behavior [Validator] Add missing translations for Bulgarian #51931 [VarExporter] Fix serializing objects that implement __sleep() and that are made lazy fix typo Document BC break with $secret parameter introduction Bump Symfony version to 6.4.0 Update VERSION for 6.4.0-RC2 Update CHANGELOG for 6.4.0-RC2 [String] Fix Inflector for 'icon' [Validator] Made tests forward-compatible with ICU 72.1
2 parents 88ffc3c + d6081c0 commit d97726e

File tree

6 files changed

+44
-18
lines changed

6 files changed

+44
-18
lines changed

Internal/Hydrator.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -262,10 +262,10 @@ public static function getPropertyScopes($class): array
262262
$name = $property->name;
263263

264264
if (\ReflectionProperty::IS_PRIVATE & $flags) {
265-
$propertyScopes["\0$class\0$name"] = $propertyScopes[$name] = [$class, $name, $flags & \ReflectionProperty::IS_READONLY ? $class : null];
265+
$propertyScopes["\0$class\0$name"] = $propertyScopes[$name] = [$class, $name, $flags & \ReflectionProperty::IS_READONLY ? $class : null, $property];
266266
continue;
267267
}
268-
$propertyScopes[$name] = [$class, $name, $flags & \ReflectionProperty::IS_READONLY ? $property->class : null];
268+
$propertyScopes[$name] = [$class, $name, $flags & \ReflectionProperty::IS_READONLY ? $property->class : null, $property];
269269

270270
if (\ReflectionProperty::IS_PROTECTED & $flags) {
271271
$propertyScopes["\0*\0$name"] = $propertyScopes[$name];
@@ -279,8 +279,8 @@ public static function getPropertyScopes($class): array
279279
if (!$property->isStatic()) {
280280
$name = $property->name;
281281
$readonlyScope = $property->isReadOnly() ? $class : null;
282-
$propertyScopes["\0$class\0$name"] = [$class, $name, $readonlyScope];
283-
$propertyScopes[$name] ??= [$class, $name, $readonlyScope];
282+
$propertyScopes["\0$class\0$name"] = [$class, $name, $readonlyScope, $property];
283+
$propertyScopes[$name] ??= [$class, $name, $readonlyScope, $property];
284284
}
285285
}
286286
}

Internal/LazyObjectState.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,11 @@ public function __construct(public readonly \Closure $initializer, $skippedPrope
4747

4848
public function initialize($instance, $propertyName, $propertyScope)
4949
{
50-
if (self::STATUS_INITIALIZED_FULL === $this->status) {
51-
return self::STATUS_INITIALIZED_FULL;
50+
if (self::STATUS_UNINITIALIZED_FULL !== $this->status) {
51+
return $this->status;
5252
}
5353

54-
$this->status = self::STATUS_INITIALIZED_FULL;
54+
$this->status = self::STATUS_INITIALIZED_PARTIAL;
5555

5656
try {
5757
if ($defaultProperties = array_diff_key(LazyObjectRegistry::$defaultProperties[$instance::class], $this->skippedProperties)) {
@@ -66,7 +66,7 @@ public function initialize($instance, $propertyName, $propertyScope)
6666
throw $e;
6767
}
6868

69-
return self::STATUS_INITIALIZED_FULL;
69+
return $this->status = self::STATUS_INITIALIZED_FULL;
7070
}
7171

7272
public function reset($instance): void

LazyGhostTrait.php

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,17 @@ public function &__get($name): mixed
106106
$state = $this->lazyObjectState ?? null;
107107

108108
if ($state && (null === $scope || isset($propertyScopes["\0$scope\0$name"]))) {
109-
$state->initialize($this, $name, $readonlyScope ?? $scope);
110-
goto get_in_scope;
109+
if (LazyObjectState::STATUS_INITIALIZED_FULL === $state->status) {
110+
// Work around php/php-src#12695
111+
$property = $propertyScopes[null === $scope ? $name : "\0$scope\0$name"][3]
112+
?? (Hydrator::$propertyScopes[$this::class] = Hydrator::getPropertyScopes($this::class))[3];
113+
} else {
114+
$property = null;
115+
}
116+
117+
if ($property?->isInitialized($this) ?? LazyObjectState::STATUS_UNINITIALIZED_PARTIAL !== $state->initialize($this, $name, $readonlyScope ?? $scope)) {
118+
goto get_in_scope;
119+
}
111120
}
112121
}
113122

@@ -169,7 +178,9 @@ public function __set($name, $value): void
169178
$scope = Registry::getScope($propertyScopes, $class, $name, $readonlyScope);
170179
$state = $this->lazyObjectState ?? null;
171180

172-
if ($state && ($readonlyScope === $scope || isset($propertyScopes["\0$scope\0$name"]))) {
181+
if ($state && ($readonlyScope === $scope || isset($propertyScopes["\0$scope\0$name"]))
182+
&& LazyObjectState::STATUS_INITIALIZED_FULL !== $state->status
183+
) {
173184
if (LazyObjectState::STATUS_UNINITIALIZED_FULL === $state->status) {
174185
$state->initialize($this, $name, $readonlyScope ?? $scope);
175186
}
@@ -202,8 +213,10 @@ public function __isset($name): bool
202213
$scope = Registry::getScope($propertyScopes, $class, $name);
203214
$state = $this->lazyObjectState ?? null;
204215

205-
if ($state && (null === $scope || isset($propertyScopes["\0$scope\0$name"]))) {
206-
$state->initialize($this, $name, $readonlyScope ?? $scope);
216+
if ($state && (null === $scope || isset($propertyScopes["\0$scope\0$name"]))
217+
&& LazyObjectState::STATUS_INITIALIZED_FULL !== $state->status
218+
&& LazyObjectState::STATUS_UNINITIALIZED_PARTIAL !== $state->initialize($this, $name, $readonlyScope ?? $scope)
219+
) {
207220
goto isset_in_scope;
208221
}
209222
}
@@ -231,7 +244,9 @@ public function __unset($name): void
231244
$scope = Registry::getScope($propertyScopes, $class, $name, $readonlyScope);
232245
$state = $this->lazyObjectState ?? null;
233246

234-
if ($state && ($readonlyScope === $scope || isset($propertyScopes["\0$scope\0$name"]))) {
247+
if ($state && ($readonlyScope === $scope || isset($propertyScopes["\0$scope\0$name"]))
248+
&& LazyObjectState::STATUS_INITIALIZED_FULL !== $state->status
249+
) {
235250
if (LazyObjectState::STATUS_UNINITIALIZED_FULL === $state->status) {
236251
$state->initialize($this, $name, $readonlyScope ?? $scope);
237252
}
@@ -286,7 +301,7 @@ public function __serialize(): array
286301
$data = [];
287302

288303
foreach (parent::__sleep() as $name) {
289-
$value = $properties[$k = $name] ?? $properties[$k = "\0*\0$name"] ?? $properties[$k = "\0$scope\0$name"] ?? $k = null;
304+
$value = $properties[$k = $name] ?? $properties[$k = "\0*\0$name"] ?? $properties[$k = "\0$class\0$name"] ?? $properties[$k = "\0$scope\0$name"] ?? $k = null;
290305

291306
if (null === $k) {
292307
trigger_error(sprintf('serialize(): "%s" returned as member variable from __sleep() but does not exist', $name), \E_USER_NOTICE);

LazyProxyTrait.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ public function __serialize(): array
295295
$data = [];
296296

297297
foreach (parent::__sleep() as $name) {
298-
$value = $properties[$k = $name] ?? $properties[$k = "\0*\0$name"] ?? $properties[$k = "\0$scope\0$name"] ?? $k = null;
298+
$value = $properties[$k = $name] ?? $properties[$k = "\0*\0$name"] ?? $properties[$k = "\0$class\0$name"] ?? $properties[$k = "\0$scope\0$name"] ?? $k = null;
299299

300300
if (null === $k) {
301301
trigger_error(sprintf('serialize(): "%s" returned as member variable from __sleep() but does not exist', $name), \E_USER_NOTICE);

ProxyHelper.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,9 @@ private static function exportPropertyScopes(string $parent): string
322322
{
323323
$propertyScopes = Hydrator::$propertyScopes[$parent] ??= Hydrator::getPropertyScopes($parent);
324324
uksort($propertyScopes, 'strnatcmp');
325+
foreach ($propertyScopes as $k => $v) {
326+
unset($propertyScopes[$k][3]);
327+
}
325328
$propertyScopes = VarExporter::export($propertyScopes);
326329
$propertyScopes = str_replace(VarExporter::export($parent), 'parent::class', $propertyScopes);
327330
$propertyScopes = preg_replace("/(?|(,)\n( ) |\n |,\n (\]))/", '$1$2', $propertyScopes);

Tests/LazyGhostTraitTest.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,10 @@ public function testUnsetPublic()
6464

6565
$this->assertSame(["\0".TestClass::class."\0lazyObjectState"], array_keys((array) $instance));
6666
unset($instance->public);
67-
$this->assertFalse(isset($instance->public));
6867
$this->assertSame(4, $instance->publicReadonly);
68+
$this->expectException(\BadMethodCallException::class);
69+
$this->expectExceptionMessage('__isset(public)');
70+
isset($instance->public);
6971
}
7072

7173
public function testSetPublic()
@@ -145,7 +147,13 @@ public function testMagicClass(MagicClass $instance)
145147
$instance->bar = 123;
146148
$serialized = serialize($instance);
147149
$clone = unserialize($serialized);
148-
$this->assertSame(123, $clone->bar);
150+
151+
if ($instance instanceof ChildMagicClass) {
152+
// ChildMagicClass redefines the $data property but not the __sleep() method
153+
$this->assertFalse(isset($clone->bar));
154+
} else {
155+
$this->assertSame(123, $clone->bar);
156+
}
149157
}
150158

151159
public static function provideMagicClass()

0 commit comments

Comments
 (0)