diff options
Diffstat (limited to 'vendor/symfony/var-exporter/LazyProxyTrait.php')
-rw-r--r-- | vendor/symfony/var-exporter/LazyProxyTrait.php | 359 |
1 files changed, 359 insertions, 0 deletions
diff --git a/vendor/symfony/var-exporter/LazyProxyTrait.php b/vendor/symfony/var-exporter/LazyProxyTrait.php new file mode 100644 index 0000000..17ba1db --- /dev/null +++ b/vendor/symfony/var-exporter/LazyProxyTrait.php | |||
@@ -0,0 +1,359 @@ | |||
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; | ||
13 | |||
14 | use Symfony\Component\Serializer\Attribute\Ignore; | ||
15 | use Symfony\Component\VarExporter\Hydrator as PublicHydrator; | ||
16 | use Symfony\Component\VarExporter\Internal\Hydrator; | ||
17 | use Symfony\Component\VarExporter\Internal\LazyObjectRegistry as Registry; | ||
18 | use Symfony\Component\VarExporter\Internal\LazyObjectState; | ||
19 | use Symfony\Component\VarExporter\Internal\LazyObjectTrait; | ||
20 | |||
21 | trait LazyProxyTrait | ||
22 | { | ||
23 | use LazyObjectTrait; | ||
24 | |||
25 | /** | ||
26 | * Creates a lazy-loading virtual proxy. | ||
27 | * | ||
28 | * @param \Closure():object $initializer Returns the proxied object | ||
29 | * @param static|null $instance | ||
30 | */ | ||
31 | public static function createLazyProxy(\Closure $initializer, ?object $instance = null): static | ||
32 | { | ||
33 | if (self::class !== $class = $instance ? $instance::class : static::class) { | ||
34 | $skippedProperties = ["\0".self::class."\0lazyObjectState" => true]; | ||
35 | } | ||
36 | |||
37 | if (!isset(Registry::$defaultProperties[$class])) { | ||
38 | Registry::$classReflectors[$class] ??= new \ReflectionClass($class); | ||
39 | $instance ??= Registry::$classReflectors[$class]->newInstanceWithoutConstructor(); | ||
40 | Registry::$defaultProperties[$class] ??= (array) $instance; | ||
41 | Registry::$classResetters[$class] ??= Registry::getClassResetters($class); | ||
42 | |||
43 | if (self::class === $class && \defined($class.'::LAZY_OBJECT_PROPERTY_SCOPES')) { | ||
44 | Hydrator::$propertyScopes[$class] ??= $class::LAZY_OBJECT_PROPERTY_SCOPES; | ||
45 | } | ||
46 | } else { | ||
47 | $instance ??= Registry::$classReflectors[$class]->newInstanceWithoutConstructor(); | ||
48 | } | ||
49 | |||
50 | $instance->lazyObjectState = new LazyObjectState($initializer); | ||
51 | |||
52 | foreach (Registry::$classResetters[$class] as $reset) { | ||
53 | $reset($instance, $skippedProperties ??= []); | ||
54 | } | ||
55 | |||
56 | return $instance; | ||
57 | } | ||
58 | |||
59 | /** | ||
60 | * Returns whether the object is initialized. | ||
61 | * | ||
62 | * @param $partial Whether partially initialized objects should be considered as initialized | ||
63 | */ | ||
64 | #[Ignore] | ||
65 | public function isLazyObjectInitialized(bool $partial = false): bool | ||
66 | { | ||
67 | return !isset($this->lazyObjectState) || isset($this->lazyObjectState->realInstance) || Registry::$noInitializerState === $this->lazyObjectState->initializer; | ||
68 | } | ||
69 | |||
70 | /** | ||
71 | * Forces initialization of a lazy object and returns it. | ||
72 | */ | ||
73 | public function initializeLazyObject(): parent | ||
74 | { | ||
75 | if ($state = $this->lazyObjectState ?? null) { | ||
76 | return $state->realInstance ??= ($state->initializer)(); | ||
77 | } | ||
78 | |||
79 | return $this; | ||
80 | } | ||
81 | |||
82 | /** | ||
83 | * @return bool Returns false when the object cannot be reset, ie when it's not a lazy object | ||
84 | */ | ||
85 | public function resetLazyObject(): bool | ||
86 | { | ||
87 | if (!isset($this->lazyObjectState) || Registry::$noInitializerState === $this->lazyObjectState->initializer) { | ||
88 | return false; | ||
89 | } | ||
90 | |||
91 | unset($this->lazyObjectState->realInstance); | ||
92 | |||
93 | return true; | ||
94 | } | ||
95 | |||
96 | public function &__get($name): mixed | ||
97 | { | ||
98 | $propertyScopes = Hydrator::$propertyScopes[$this::class] ??= Hydrator::getPropertyScopes($this::class); | ||
99 | $scope = null; | ||
100 | $instance = $this; | ||
101 | |||
102 | if ([$class, , $readonlyScope] = $propertyScopes[$name] ?? null) { | ||
103 | $scope = Registry::getScope($propertyScopes, $class, $name); | ||
104 | |||
105 | if (null === $scope || isset($propertyScopes["\0$scope\0$name"])) { | ||
106 | if ($state = $this->lazyObjectState ?? null) { | ||
107 | $instance = $state->realInstance ??= ($state->initializer)(); | ||
108 | } | ||
109 | $parent = 2; | ||
110 | goto get_in_scope; | ||
111 | } | ||
112 | } | ||
113 | $parent = (Registry::$parentMethods[self::class] ??= Registry::getParentMethods(self::class))['get']; | ||
114 | |||
115 | if ($state = $this->lazyObjectState ?? null) { | ||
116 | $instance = $state->realInstance ??= ($state->initializer)(); | ||
117 | } else { | ||
118 | if (2 === $parent) { | ||
119 | return parent::__get($name); | ||
120 | } | ||
121 | $value = parent::__get($name); | ||
122 | |||
123 | return $value; | ||
124 | } | ||
125 | |||
126 | if (!$parent && null === $class && !\array_key_exists($name, (array) $instance)) { | ||
127 | $frame = debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0]; | ||
128 | trigger_error(sprintf('Undefined property: %s::$%s in %s on line %s', $instance::class, $name, $frame['file'], $frame['line']), \E_USER_NOTICE); | ||
129 | } | ||
130 | |||
131 | get_in_scope: | ||
132 | |||
133 | try { | ||
134 | if (null === $scope) { | ||
135 | if (null === $readonlyScope && 1 !== $parent) { | ||
136 | return $instance->$name; | ||
137 | } | ||
138 | $value = $instance->$name; | ||
139 | |||
140 | return $value; | ||
141 | } | ||
142 | $accessor = Registry::$classAccessors[$scope] ??= Registry::getClassAccessors($scope); | ||
143 | |||
144 | return $accessor['get']($instance, $name, null !== $readonlyScope || 1 === $parent); | ||
145 | } catch (\Error $e) { | ||
146 | if (\Error::class !== $e::class || !str_starts_with($e->getMessage(), 'Cannot access uninitialized non-nullable property')) { | ||
147 | throw $e; | ||
148 | } | ||
149 | |||
150 | try { | ||
151 | if (null === $scope) { | ||
152 | $instance->$name = []; | ||
153 | |||
154 | return $instance->$name; | ||
155 | } | ||
156 | |||
157 | $accessor['set']($instance, $name, []); | ||
158 | |||
159 | return $accessor['get']($instance, $name, null !== $readonlyScope || 1 === $parent); | ||
160 | } catch (\Error) { | ||
161 | throw $e; | ||
162 | } | ||
163 | } | ||
164 | } | ||
165 | |||
166 | public function __set($name, $value): void | ||
167 | { | ||
168 | $propertyScopes = Hydrator::$propertyScopes[$this::class] ??= Hydrator::getPropertyScopes($this::class); | ||
169 | $scope = null; | ||
170 | $instance = $this; | ||
171 | |||
172 | if ([$class, , $readonlyScope] = $propertyScopes[$name] ?? null) { | ||
173 | $scope = Registry::getScope($propertyScopes, $class, $name, $readonlyScope); | ||
174 | |||
175 | if ($readonlyScope === $scope || isset($propertyScopes["\0$scope\0$name"])) { | ||
176 | if ($state = $this->lazyObjectState ?? null) { | ||
177 | $instance = $state->realInstance ??= ($state->initializer)(); | ||
178 | } | ||
179 | goto set_in_scope; | ||
180 | } | ||
181 | } | ||
182 | |||
183 | if ($state = $this->lazyObjectState ?? null) { | ||
184 | $instance = $state->realInstance ??= ($state->initializer)(); | ||
185 | } elseif ((Registry::$parentMethods[self::class] ??= Registry::getParentMethods(self::class))['set']) { | ||
186 | parent::__set($name, $value); | ||
187 | |||
188 | return; | ||
189 | } | ||
190 | |||
191 | set_in_scope: | ||
192 | |||
193 | if (null === $scope) { | ||
194 | $instance->$name = $value; | ||
195 | } else { | ||
196 | $accessor = Registry::$classAccessors[$scope] ??= Registry::getClassAccessors($scope); | ||
197 | $accessor['set']($instance, $name, $value); | ||
198 | } | ||
199 | } | ||
200 | |||
201 | public function __isset($name): bool | ||
202 | { | ||
203 | $propertyScopes = Hydrator::$propertyScopes[$this::class] ??= Hydrator::getPropertyScopes($this::class); | ||
204 | $scope = null; | ||
205 | $instance = $this; | ||
206 | |||
207 | if ([$class] = $propertyScopes[$name] ?? null) { | ||
208 | $scope = Registry::getScope($propertyScopes, $class, $name); | ||
209 | |||
210 | if (null === $scope || isset($propertyScopes["\0$scope\0$name"])) { | ||
211 | if ($state = $this->lazyObjectState ?? null) { | ||
212 | $instance = $state->realInstance ??= ($state->initializer)(); | ||
213 | } | ||
214 | goto isset_in_scope; | ||
215 | } | ||
216 | } | ||
217 | |||
218 | if ($state = $this->lazyObjectState ?? null) { | ||
219 | $instance = $state->realInstance ??= ($state->initializer)(); | ||
220 | } elseif ((Registry::$parentMethods[self::class] ??= Registry::getParentMethods(self::class))['isset']) { | ||
221 | return parent::__isset($name); | ||
222 | } | ||
223 | |||
224 | isset_in_scope: | ||
225 | |||
226 | if (null === $scope) { | ||
227 | return isset($instance->$name); | ||
228 | } | ||
229 | $accessor = Registry::$classAccessors[$scope] ??= Registry::getClassAccessors($scope); | ||
230 | |||
231 | return $accessor['isset']($instance, $name); | ||
232 | } | ||
233 | |||
234 | public function __unset($name): void | ||
235 | { | ||
236 | $propertyScopes = Hydrator::$propertyScopes[$this::class] ??= Hydrator::getPropertyScopes($this::class); | ||
237 | $scope = null; | ||
238 | $instance = $this; | ||
239 | |||
240 | if ([$class, , $readonlyScope] = $propertyScopes[$name] ?? null) { | ||
241 | $scope = Registry::getScope($propertyScopes, $class, $name, $readonlyScope); | ||
242 | |||
243 | if ($readonlyScope === $scope || isset($propertyScopes["\0$scope\0$name"])) { | ||
244 | if ($state = $this->lazyObjectState ?? null) { | ||
245 | $instance = $state->realInstance ??= ($state->initializer)(); | ||
246 | } | ||
247 | goto unset_in_scope; | ||
248 | } | ||
249 | } | ||
250 | |||
251 | if ($state = $this->lazyObjectState ?? null) { | ||
252 | $instance = $state->realInstance ??= ($state->initializer)(); | ||
253 | } elseif ((Registry::$parentMethods[self::class] ??= Registry::getParentMethods(self::class))['unset']) { | ||
254 | parent::__unset($name); | ||
255 | |||
256 | return; | ||
257 | } | ||
258 | |||
259 | unset_in_scope: | ||
260 | |||
261 | if (null === $scope) { | ||
262 | unset($instance->$name); | ||
263 | } else { | ||
264 | $accessor = Registry::$classAccessors[$scope] ??= Registry::getClassAccessors($scope); | ||
265 | $accessor['unset']($instance, $name); | ||
266 | } | ||
267 | } | ||
268 | |||
269 | public function __clone(): void | ||
270 | { | ||
271 | if (!isset($this->lazyObjectState)) { | ||
272 | if ((Registry::$parentMethods[self::class] ??= Registry::getParentMethods(self::class))['clone']) { | ||
273 | parent::__clone(); | ||
274 | } | ||
275 | |||
276 | return; | ||
277 | } | ||
278 | |||
279 | $this->lazyObjectState = clone $this->lazyObjectState; | ||
280 | |||
281 | if (isset($this->lazyObjectState->realInstance)) { | ||
282 | $this->lazyObjectState->realInstance = clone $this->lazyObjectState->realInstance; | ||
283 | } | ||
284 | } | ||
285 | |||
286 | public function __serialize(): array | ||
287 | { | ||
288 | $class = self::class; | ||
289 | $state = $this->lazyObjectState ?? null; | ||
290 | |||
291 | if (!$state && (Registry::$parentMethods[$class] ??= Registry::getParentMethods($class))['serialize']) { | ||
292 | $properties = parent::__serialize(); | ||
293 | } else { | ||
294 | $properties = (array) $this; | ||
295 | |||
296 | if ($state) { | ||
297 | unset($properties["\0$class\0lazyObjectState"]); | ||
298 | $properties["\0$class\0lazyObjectReal"] = $state->realInstance ??= ($state->initializer)(); | ||
299 | } | ||
300 | } | ||
301 | |||
302 | if ($state || Registry::$parentMethods[$class]['serialize'] || !Registry::$parentMethods[$class]['sleep']) { | ||
303 | return $properties; | ||
304 | } | ||
305 | |||
306 | $scope = get_parent_class($class); | ||
307 | $data = []; | ||
308 | |||
309 | foreach (parent::__sleep() as $name) { | ||
310 | $value = $properties[$k = $name] ?? $properties[$k = "\0*\0$name"] ?? $properties[$k = "\0$class\0$name"] ?? $properties[$k = "\0$scope\0$name"] ?? $k = null; | ||
311 | |||
312 | if (null === $k) { | ||
313 | trigger_error(sprintf('serialize(): "%s" returned as member variable from __sleep() but does not exist', $name), \E_USER_NOTICE); | ||
314 | } else { | ||
315 | $data[$k] = $value; | ||
316 | } | ||
317 | } | ||
318 | |||
319 | return $data; | ||
320 | } | ||
321 | |||
322 | public function __unserialize(array $data): void | ||
323 | { | ||
324 | $class = self::class; | ||
325 | |||
326 | if ($instance = $data["\0$class\0lazyObjectReal"] ?? null) { | ||
327 | unset($data["\0$class\0lazyObjectReal"]); | ||
328 | |||
329 | foreach (Registry::$classResetters[$class] ??= Registry::getClassResetters($class) as $reset) { | ||
330 | $reset($this, $data); | ||
331 | } | ||
332 | |||
333 | if ($data) { | ||
334 | PublicHydrator::hydrate($this, $data); | ||
335 | } | ||
336 | $this->lazyObjectState = new LazyObjectState(Registry::$noInitializerState ??= static fn () => throw new \LogicException('Lazy proxy has no initializer.')); | ||
337 | $this->lazyObjectState->realInstance = $instance; | ||
338 | } elseif ((Registry::$parentMethods[$class] ??= Registry::getParentMethods($class))['unserialize']) { | ||
339 | parent::__unserialize($data); | ||
340 | } else { | ||
341 | PublicHydrator::hydrate($this, $data); | ||
342 | |||
343 | if (Registry::$parentMethods[$class]['wakeup']) { | ||
344 | parent::__wakeup(); | ||
345 | } | ||
346 | } | ||
347 | } | ||
348 | |||
349 | public function __destruct() | ||
350 | { | ||
351 | if (isset($this->lazyObjectState)) { | ||
352 | return; | ||
353 | } | ||
354 | |||
355 | if ((Registry::$parentMethods[self::class] ??= Registry::getParentMethods(self::class))['destruct']) { | ||
356 | parent::__destruct(); | ||
357 | } | ||
358 | } | ||
359 | } | ||