Skip to content

Commit 10ce968

Browse files
[VarExporter] Remove LazyGhostTrait and LazyProxyTrait in favor of native lazy objects
1 parent 5a700f2 commit 10ce968

22 files changed

+27
-1679
lines changed

UPGRADE-8.0.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,10 @@ TwigBridge
1616
----------
1717

1818
* Remove `text` format from the `debug:twig` command, use the `txt` format instead
19+
20+
VarExporter
21+
-----------
22+
23+
* Restrict `ProxyHelper::generateLazyProxy()` to generating abstraction-based lazy decorators; use native lazy proxies otherwise
24+
* Remove `LazyGhostTrait` and `LazyProxyTrait`, use native lazy objects instead
25+
* Remove `ProxyHelper::generateLazyGhost()`, use native lazy objects instead

src/Symfony/Component/VarExporter/CHANGELOG.md

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

4+
8.0
5+
---
6+
7+
* Restrict `ProxyHelper::generateLazyProxy()` to generating abstraction-based lazy decorators; use native lazy proxies otherwise
8+
* Remove `LazyGhostTrait` and `LazyProxyTrait`, use native lazy objects instead
9+
* Remove `ProxyHelper::generateLazyGhost()`, use native lazy objects instead
10+
411
7.3
512
---
613

src/Symfony/Component/VarExporter/Internal/LazyDecoratorTrait.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ public function &__get($name): mixed
9595
$notByRef = $access & Hydrator::PROPERTY_NOT_BY_REF || ($access >> 2) & \ReflectionProperty::IS_PRIVATE_SET;
9696
}
9797

98-
if ($notByRef || 2 !== ((Registry::$parentMethods[$class] ??= Registry::getParentMethods($class))['get'] ?: 2)) {
98+
if ($notByRef || 2 !== ((Registry::$parentGet[$class] ??= Registry::getParentGet($class)) ?: 2)) {
9999
$value = $instance->$name;
100100

101101
return $value;

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

Lines changed: 7 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,9 @@ class LazyObjectRegistry
4141
public static array $classAccessors = [];
4242

4343
/**
44-
* @var array<class-string, array{set: bool, isset: bool, unset: bool, clone: bool, serialize: bool, unserialize: bool, sleep: bool, wakeup: bool, destruct: bool, get: int}>
44+
* @var array<class-string, int}>
4545
*/
46-
public static array $parentMethods = [];
47-
48-
public static ?\Closure $noInitializerState = null;
46+
public static array $parentGet = [];
4947

5048
public static function getClassResetters($class)
5149
{
@@ -86,80 +84,16 @@ public static function getClassResetters($class)
8684
return $resetters;
8785
}
8886

89-
public static function getClassAccessors($class)
90-
{
91-
return \Closure::bind(static fn () => [
92-
'get' => static function &($instance, $name, $notByRef) {
93-
if (!$notByRef) {
94-
return $instance->$name;
95-
}
96-
$value = $instance->$name;
97-
98-
return $value;
99-
},
100-
'set' => static function ($instance, $name, $value) {
101-
$instance->$name = $value;
102-
},
103-
'isset' => static fn ($instance, $name) => isset($instance->$name),
104-
'unset' => static function ($instance, $name) {
105-
unset($instance->$name);
106-
},
107-
], null, \Closure::class === $class ? null : $class)();
108-
}
109-
110-
public static function getParentMethods($class)
87+
public static function getParentGet($class): int
11188
{
11289
$parent = get_parent_class($class);
113-
$methods = [];
114-
115-
foreach (['set', 'isset', 'unset', 'clone', 'serialize', 'unserialize', 'sleep', 'wakeup', 'destruct', 'get'] as $method) {
116-
if (!$parent || !method_exists($parent, '__'.$method)) {
117-
$methods[$method] = false;
118-
} else {
119-
$m = new \ReflectionMethod($parent, '__'.$method);
120-
$methods[$method] = !$m->isAbstract() && !$m->isPrivate();
121-
}
122-
}
123-
124-
$methods['get'] = $methods['get'] ? ($m->returnsReference() ? 2 : 1) : 0;
125-
126-
return $methods;
127-
}
12890

129-
public static function getScopeForRead($propertyScopes, $class, $property)
130-
{
131-
if (!isset($propertyScopes[$k = "\0$class\0$property"]) && !isset($propertyScopes[$k = "\0*\0$property"])) {
132-
return null;
133-
}
134-
$frame = debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT | \DEBUG_BACKTRACE_IGNORE_ARGS, 3)[2];
135-
136-
if (\ReflectionProperty::class === $scope = $frame['class'] ?? \Closure::class) {
137-
$scope = $frame['object']->class;
138-
}
139-
if ('*' === $k[1] && ($class === $scope || (is_subclass_of($class, $scope) && !isset($propertyScopes["\0$scope\0$property"])))) {
140-
return null;
141-
}
142-
143-
return $scope;
144-
}
145-
146-
public static function getScopeForWrite($propertyScopes, $class, $property, $flags)
147-
{
148-
if (!($flags & (\ReflectionProperty::IS_PRIVATE | \ReflectionProperty::IS_PROTECTED | \ReflectionProperty::IS_READONLY | \ReflectionProperty::IS_PRIVATE_SET))) {
149-
return null;
91+
if (!$parent || !method_exists($parent, '__get')) {
92+
return 0;
15093
}
151-
$frame = debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT | \DEBUG_BACKTRACE_IGNORE_ARGS, 3)[2];
15294

153-
if (\ReflectionProperty::class === $scope = $frame['class'] ?? \Closure::class) {
154-
$scope = $frame['object']->class;
155-
}
156-
if ($flags & (\ReflectionProperty::IS_PRIVATE | \ReflectionProperty::IS_PRIVATE_SET)) {
157-
return $scope;
158-
}
159-
if ($flags & (\ReflectionProperty::IS_PROTECTED | \ReflectionProperty::IS_PROTECTED_SET) && ($class === $scope || (is_subclass_of($class, $scope) && !isset($propertyScopes["\0$scope\0$property"])))) {
160-
return null;
161-
}
95+
$m = new \ReflectionMethod($parent, '__get');
16296

163-
return $scope;
97+
return !$m->isAbstract() && !$m->isPrivate() ? ($m->returnsReference() ? 2 : 1) : 0;
16498
}
16599
}

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

Lines changed: 1 addition & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -22,80 +22,10 @@
2222
*/
2323
class LazyObjectState
2424
{
25-
public const STATUS_UNINITIALIZED_FULL = 1;
26-
public const STATUS_UNINITIALIZED_PARTIAL = 2;
27-
public const STATUS_INITIALIZED_FULL = 3;
28-
public const STATUS_INITIALIZED_PARTIAL = 4;
29-
30-
/**
31-
* @var self::STATUS_*
32-
*/
33-
public int $status = self::STATUS_UNINITIALIZED_FULL;
34-
25+
public ?\Closure $initializer = null;
3526
public object $realInstance;
3627
public object $cloneInstance;
3728

38-
/**
39-
* @param array<string, true> $skippedProperties
40-
*/
41-
public function __construct(
42-
public ?\Closure $initializer = null,
43-
public array $skippedProperties = [],
44-
) {
45-
}
46-
47-
public function initialize($instance, $propertyName, $writeScope)
48-
{
49-
if (self::STATUS_UNINITIALIZED_FULL !== $this->status) {
50-
return $this->status;
51-
}
52-
53-
$this->status = self::STATUS_INITIALIZED_PARTIAL;
54-
55-
try {
56-
if ($defaultProperties = array_diff_key(LazyObjectRegistry::$defaultProperties[$instance::class], $this->skippedProperties)) {
57-
PublicHydrator::hydrate($instance, $defaultProperties);
58-
}
59-
60-
($this->initializer)($instance);
61-
} catch (\Throwable $e) {
62-
$this->status = self::STATUS_UNINITIALIZED_FULL;
63-
$this->reset($instance);
64-
65-
throw $e;
66-
}
67-
68-
return $this->status = self::STATUS_INITIALIZED_FULL;
69-
}
70-
71-
public function reset($instance): void
72-
{
73-
$class = $instance::class;
74-
$propertyScopes = Hydrator::$propertyScopes[$class] ??= Hydrator::getPropertyScopes($class);
75-
$skippedProperties = $this->skippedProperties;
76-
$properties = (array) $instance;
77-
78-
foreach ($propertyScopes as $key => [$scope, $name, , $access]) {
79-
$propertyScopes[$k = "\0$scope\0$name"] ?? $propertyScopes[$k = "\0*\0$name"] ?? $k = $name;
80-
81-
if ($k === $key && ($access & Hydrator::PROPERTY_HAS_HOOKS || ($access >> 2) & \ReflectionProperty::IS_READONLY || !\array_key_exists($k, $properties))) {
82-
$skippedProperties[$k] = true;
83-
}
84-
}
85-
86-
foreach (LazyObjectRegistry::$classResetters[$class] as $reset) {
87-
$reset($instance, $skippedProperties);
88-
}
89-
90-
foreach ((array) $instance as $name => $value) {
91-
if ("\0" !== ($name[0] ?? '') && !\array_key_exists($name, $skippedProperties)) {
92-
unset($instance->$name);
93-
}
94-
}
95-
96-
$this->status = self::STATUS_UNINITIALIZED_FULL;
97-
}
98-
9929
public function __clone()
10030
{
10131
if (isset($this->cloneInstance)) {

src/Symfony/Component/VarExporter/Internal/LazyObjectTrait.php

Lines changed: 0 additions & 23 deletions
This file was deleted.

0 commit comments

Comments
 (0)