update lock clucknut
All checks were successful
All checks were successful
This commit is contained in:
@@ -145,7 +145,7 @@ public static function prepare($values, $objectsPool, &$refsPool, &$objectsCount
|
||||
$p = $parent->hasProperty($n) ? $parent->getProperty($n) : null;
|
||||
} while (!$p && $parent = $parent->getParentClass());
|
||||
|
||||
$c = $p && (!$p->isPublic() || $p->isProtectedSet() || $p->isPrivateSet()) ? $p->class : 'stdClass';
|
||||
$c = $p && (!$p->isPublic() || (\PHP_VERSION_ID >= 80400 ? $p->isProtectedSet() || $p->isPrivateSet() : $p->isReadOnly())) ? $p->class : 'stdClass';
|
||||
} elseif ('*' === $n[1]) {
|
||||
$n = substr($n, 3);
|
||||
$c = $reflector->getProperty($n)->class;
|
||||
|
||||
@@ -222,7 +222,7 @@ public static function getSimpleHydrator($class)
|
||||
if ($propertyReflector->isStatic()) {
|
||||
continue;
|
||||
}
|
||||
if (!$propertyReflector->isAbstract() && $propertyReflector->getHooks()) {
|
||||
if (\PHP_VERSION_ID >= 80400 && !$propertyReflector->isAbstract() && $propertyReflector->getHooks()) {
|
||||
$notByRef->{$propertyReflector->name} = $propertyReflector->setRawValue(...);
|
||||
} elseif ($propertyReflector->isReadOnly()) {
|
||||
$notByRef->{$propertyReflector->name} = static function ($object, $value) use ($propertyReflector) {
|
||||
@@ -277,7 +277,7 @@ public static function getPropertyScopes($class): array
|
||||
$name = $property->name;
|
||||
$access = ($flags << 2) | ($flags & \ReflectionProperty::IS_READONLY ? self::PROPERTY_NOT_BY_REF : 0);
|
||||
|
||||
if (!$property->isAbstract() && $h = $property->getHooks()) {
|
||||
if (\PHP_VERSION_ID >= 80400 && !$property->isAbstract() && $h = $property->getHooks()) {
|
||||
$access |= self::PROPERTY_HAS_HOOKS | (isset($h['get']) && !$h['get']->returnsReference() ? self::PROPERTY_NOT_BY_REF : 0);
|
||||
}
|
||||
|
||||
@@ -289,7 +289,7 @@ public static function getPropertyScopes($class): array
|
||||
|
||||
$propertyScopes[$name] = [$class, $name, null, $access, $property];
|
||||
|
||||
if ($flags & \ReflectionProperty::IS_PRIVATE_SET) {
|
||||
if ($flags & (\PHP_VERSION_ID >= 80400 ? \ReflectionProperty::IS_PRIVATE_SET : \ReflectionProperty::IS_READONLY)) {
|
||||
$propertyScopes[$name][2] = $property->class;
|
||||
}
|
||||
|
||||
@@ -310,7 +310,7 @@ public static function getPropertyScopes($class): array
|
||||
$name = $property->name;
|
||||
$access = ($flags << 2) | ($flags & \ReflectionProperty::IS_READONLY ? self::PROPERTY_NOT_BY_REF : 0);
|
||||
|
||||
if ($h = $property->getHooks()) {
|
||||
if (\PHP_VERSION_ID >= 80400 && $h = $property->getHooks()) {
|
||||
$access |= self::PROPERTY_HAS_HOOKS | (isset($h['get']) && !$h['get']->returnsReference() ? self::PROPERTY_NOT_BY_REF : 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ public function &__get($name): mixed
|
||||
$notByRef = $access & Hydrator::PROPERTY_NOT_BY_REF || ($access >> 2) & \ReflectionProperty::IS_PRIVATE_SET;
|
||||
}
|
||||
|
||||
if ($notByRef || 2 !== ((Registry::$parentGet[$class] ??= Registry::getParentGet($class)) ?: 2)) {
|
||||
if ($notByRef || 2 !== ((Registry::$parentMethods[$class] ??= Registry::getParentMethods($class))['get'] ?: 2)) {
|
||||
$value = $instance->$name;
|
||||
|
||||
return $value;
|
||||
|
||||
@@ -41,9 +41,11 @@ class LazyObjectRegistry
|
||||
public static array $classAccessors = [];
|
||||
|
||||
/**
|
||||
* @var array<class-string, int>
|
||||
* @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}>
|
||||
*/
|
||||
public static array $parentGet = [];
|
||||
public static array $parentMethods = [];
|
||||
|
||||
public static ?\Closure $noInitializerState = null;
|
||||
|
||||
public static function getClassResetters($class)
|
||||
{
|
||||
@@ -84,16 +86,80 @@ public static function getClassResetters($class)
|
||||
return $resetters;
|
||||
}
|
||||
|
||||
public static function getParentGet($class): int
|
||||
public static function getClassAccessors($class)
|
||||
{
|
||||
return \Closure::bind(static fn () => [
|
||||
'get' => static function &($instance, $name, $notByRef) {
|
||||
if (!$notByRef) {
|
||||
return $instance->$name;
|
||||
}
|
||||
$value = $instance->$name;
|
||||
|
||||
return $value;
|
||||
},
|
||||
'set' => static function ($instance, $name, $value) {
|
||||
$instance->$name = $value;
|
||||
},
|
||||
'isset' => static fn ($instance, $name) => isset($instance->$name),
|
||||
'unset' => static function ($instance, $name) {
|
||||
unset($instance->$name);
|
||||
},
|
||||
], null, \Closure::class === $class ? null : $class)();
|
||||
}
|
||||
|
||||
public static function getParentMethods($class)
|
||||
{
|
||||
$parent = get_parent_class($class);
|
||||
$methods = [];
|
||||
|
||||
if (!$parent || !method_exists($parent, '__get')) {
|
||||
return 0;
|
||||
foreach (['set', 'isset', 'unset', 'clone', 'serialize', 'unserialize', 'sleep', 'wakeup', 'destruct', 'get'] as $method) {
|
||||
if (!$parent || !method_exists($parent, '__'.$method)) {
|
||||
$methods[$method] = false;
|
||||
} else {
|
||||
$m = new \ReflectionMethod($parent, '__'.$method);
|
||||
$methods[$method] = !$m->isAbstract() && !$m->isPrivate();
|
||||
}
|
||||
}
|
||||
|
||||
$m = new \ReflectionMethod($parent, '__get');
|
||||
$methods['get'] = $methods['get'] ? ($m->returnsReference() ? 2 : 1) : 0;
|
||||
|
||||
return !$m->isAbstract() && !$m->isPrivate() ? ($m->returnsReference() ? 2 : 1) : 0;
|
||||
return $methods;
|
||||
}
|
||||
|
||||
public static function getScopeForRead($propertyScopes, $class, $property)
|
||||
{
|
||||
if (!isset($propertyScopes[$k = "\0$class\0$property"]) && !isset($propertyScopes[$k = "\0*\0$property"])) {
|
||||
return null;
|
||||
}
|
||||
$frame = debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT | \DEBUG_BACKTRACE_IGNORE_ARGS, 3)[2];
|
||||
|
||||
if (\ReflectionProperty::class === $scope = $frame['class'] ?? \Closure::class) {
|
||||
$scope = $frame['object']->class;
|
||||
}
|
||||
if ('*' === $k[1] && ($class === $scope || (is_subclass_of($class, $scope) && !isset($propertyScopes["\0$scope\0$property"])))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $scope;
|
||||
}
|
||||
|
||||
public static function getScopeForWrite($propertyScopes, $class, $property, $flags)
|
||||
{
|
||||
if (!($flags & (\ReflectionProperty::IS_PRIVATE | \ReflectionProperty::IS_PROTECTED | \ReflectionProperty::IS_READONLY | (\PHP_VERSION_ID >= 80400 ? \ReflectionProperty::IS_PRIVATE_SET | \ReflectionProperty::IS_PROTECTED_SET : 0)))) {
|
||||
return null;
|
||||
}
|
||||
$frame = debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT | \DEBUG_BACKTRACE_IGNORE_ARGS, 3)[2];
|
||||
|
||||
if (\ReflectionProperty::class === $scope = $frame['class'] ?? \Closure::class) {
|
||||
$scope = $frame['object']->class;
|
||||
}
|
||||
if ($flags & (\ReflectionProperty::IS_PRIVATE | (\PHP_VERSION_ID >= 80400 ? \ReflectionProperty::IS_PRIVATE_SET : \ReflectionProperty::IS_READONLY))) {
|
||||
return $scope;
|
||||
}
|
||||
if ($flags & (\ReflectionProperty::IS_PROTECTED | (\PHP_VERSION_ID >= 80400 ? \ReflectionProperty::IS_PROTECTED_SET : 0)) && ($class === $scope || (is_subclass_of($class, $scope) && !isset($propertyScopes["\0$scope\0$property"])))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $scope;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
|
||||
namespace Symfony\Component\VarExporter\Internal;
|
||||
|
||||
use Symfony\Component\VarExporter\Hydrator as PublicHydrator;
|
||||
|
||||
/**
|
||||
* Keeps the state of lazy objects.
|
||||
*
|
||||
@@ -20,10 +22,80 @@
|
||||
*/
|
||||
class LazyObjectState
|
||||
{
|
||||
public ?\Closure $initializer = null;
|
||||
public const STATUS_UNINITIALIZED_FULL = 1;
|
||||
public const STATUS_UNINITIALIZED_PARTIAL = 2;
|
||||
public const STATUS_INITIALIZED_FULL = 3;
|
||||
public const STATUS_INITIALIZED_PARTIAL = 4;
|
||||
|
||||
/**
|
||||
* @var self::STATUS_*
|
||||
*/
|
||||
public int $status = self::STATUS_UNINITIALIZED_FULL;
|
||||
|
||||
public object $realInstance;
|
||||
public object $cloneInstance;
|
||||
|
||||
/**
|
||||
* @param array<string, true> $skippedProperties
|
||||
*/
|
||||
public function __construct(
|
||||
public ?\Closure $initializer = null,
|
||||
public array $skippedProperties = [],
|
||||
) {
|
||||
}
|
||||
|
||||
public function initialize($instance, $propertyName, $writeScope)
|
||||
{
|
||||
if (self::STATUS_UNINITIALIZED_FULL !== $this->status) {
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
$this->status = self::STATUS_INITIALIZED_PARTIAL;
|
||||
|
||||
try {
|
||||
if ($defaultProperties = array_diff_key(LazyObjectRegistry::$defaultProperties[$instance::class], $this->skippedProperties)) {
|
||||
PublicHydrator::hydrate($instance, $defaultProperties);
|
||||
}
|
||||
|
||||
($this->initializer)($instance);
|
||||
} catch (\Throwable $e) {
|
||||
$this->status = self::STATUS_UNINITIALIZED_FULL;
|
||||
$this->reset($instance);
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return $this->status = self::STATUS_INITIALIZED_FULL;
|
||||
}
|
||||
|
||||
public function reset($instance): void
|
||||
{
|
||||
$class = $instance::class;
|
||||
$propertyScopes = Hydrator::$propertyScopes[$class] ??= Hydrator::getPropertyScopes($class);
|
||||
$skippedProperties = $this->skippedProperties;
|
||||
$properties = (array) $instance;
|
||||
|
||||
foreach ($propertyScopes as $key => [$scope, $name, , $access]) {
|
||||
$propertyScopes[$k = "\0$scope\0$name"] ?? $propertyScopes[$k = "\0*\0$name"] ?? $k = $name;
|
||||
|
||||
if ($k === $key && ($access & Hydrator::PROPERTY_HAS_HOOKS || ($access >> 2) & \ReflectionProperty::IS_READONLY || !\array_key_exists($k, $properties))) {
|
||||
$skippedProperties[$k] = true;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (LazyObjectRegistry::$classResetters[$class] as $reset) {
|
||||
$reset($instance, $skippedProperties);
|
||||
}
|
||||
|
||||
foreach ((array) $instance as $name => $value) {
|
||||
if ("\0" !== ($name[0] ?? '') && !\array_key_exists($name, $skippedProperties)) {
|
||||
unset($instance->$name);
|
||||
}
|
||||
}
|
||||
|
||||
$this->status = self::STATUS_UNINITIALIZED_FULL;
|
||||
}
|
||||
|
||||
public function __clone()
|
||||
{
|
||||
if (isset($this->cloneInstance)) {
|
||||
|
||||
34
vendor/symfony/var-exporter/Internal/LazyObjectTrait.php
vendored
Normal file
34
vendor/symfony/var-exporter/Internal/LazyObjectTrait.php
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\VarExporter\Internal;
|
||||
|
||||
use Symfony\Component\Serializer\Attribute\Ignore;
|
||||
|
||||
if (\PHP_VERSION_ID >= 80300) {
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
trait LazyObjectTrait
|
||||
{
|
||||
#[Ignore]
|
||||
private readonly LazyObjectState $lazyObjectState;
|
||||
}
|
||||
} else {
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
trait LazyObjectTrait
|
||||
{
|
||||
#[Ignore]
|
||||
private LazyObjectState $lazyObjectState;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user