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 | } | ||
