Viewing file: Hydrator.php (10.12 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
<?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\VarExporter\Exception\ClassNotFoundException;
/** * @author Nicolas Grekas <p@tchwork.com> * * @internal */ class Hydrator { public static array $hydrators = []; public static array $simpleHydrators = []; public static array $propertyScopes = [];
public function __construct( public readonly Registry $registry, public readonly ?Values $values, public readonly array $properties, public readonly mixed $value, public readonly array $wakeups, ) { }
public static function hydrate($objects, $values, $properties, $value, $wakeups) { foreach ($properties as $class => $vars) { (self::$hydrators[$class] ??= self::getHydrator($class))($vars, $objects); } foreach ($wakeups as $k => $v) { if (\is_array($v)) { $objects[-$k]->__unserialize($v); } else { $objects[$v]->__wakeup(); } }
return $value; }
public static function getHydrator($class) { $baseHydrator = self::$hydrators['stdClass'] ??= static function ($properties, $objects) { foreach ($properties as $name => $values) { foreach ($values as $i => $v) { $objects[$i]->$name = $v; } } };
switch ($class) { case 'stdClass': return $baseHydrator;
case 'ErrorException': return $baseHydrator->bindTo(null, new class() extends \ErrorException { });
case 'TypeError': return $baseHydrator->bindTo(null, new class() extends \Error { });
case 'SplObjectStorage': return static function ($properties, $objects) { foreach ($properties as $name => $values) { if ("\0" === $name) { foreach ($values as $i => $v) { for ($j = 0; $j < \count($v); ++$j) { $objects[$i]->attach($v[$j], $v[++$j]); } } continue; } foreach ($values as $i => $v) { $objects[$i]->$name = $v; } } }; }
if (!class_exists($class) && !interface_exists($class, false) && !trait_exists($class, false)) { throw new ClassNotFoundException($class); } $classReflector = new \ReflectionClass($class);
switch ($class) { case 'ArrayIterator': case 'ArrayObject': $constructor = $classReflector->getConstructor()->invokeArgs(...);
return static function ($properties, $objects) use ($constructor) { foreach ($properties as $name => $values) { if ("\0" !== $name) { foreach ($values as $i => $v) { $objects[$i]->$name = $v; } } } foreach ($properties["\0"] ?? [] as $i => $v) { $constructor($objects[$i], $v); } }; }
if (!$classReflector->isInternal()) { return $baseHydrator->bindTo(null, $class); }
if ($classReflector->name !== $class) { return self::$hydrators[$classReflector->name] ??= self::getHydrator($classReflector->name); }
$propertySetters = []; foreach ($classReflector->getProperties() as $propertyReflector) { if (!$propertyReflector->isStatic()) { $propertySetters[$propertyReflector->name] = $propertyReflector->setValue(...); } }
if (!$propertySetters) { return $baseHydrator; }
return static function ($properties, $objects) use ($propertySetters) { foreach ($properties as $name => $values) { if ($setValue = $propertySetters[$name] ?? null) { foreach ($values as $i => $v) { $setValue($objects[$i], $v); } continue; } foreach ($values as $i => $v) { $objects[$i]->$name = $v; } } }; }
public static function getSimpleHydrator($class) { $baseHydrator = self::$simpleHydrators['stdClass'] ??= (function ($properties, $object) { $readonly = (array) $this;
foreach ($properties as $name => &$value) { $object->$name = $value;
if (!($readonly[$name] ?? false)) { $object->$name = &$value; } } })->bindTo(new \stdClass());
switch ($class) { case 'stdClass': return $baseHydrator;
case 'ErrorException': return $baseHydrator->bindTo(new \stdClass(), new class() extends \ErrorException { });
case 'TypeError': return $baseHydrator->bindTo(new \stdClass(), new class() extends \Error { });
case 'SplObjectStorage': return static function ($properties, $object) { foreach ($properties as $name => &$value) { if ("\0" !== $name) { $object->$name = $value; $object->$name = &$value; continue; } for ($i = 0; $i < \count($value); ++$i) { $object->attach($value[$i], $value[++$i]); } } }; }
if (!class_exists($class) && !interface_exists($class, false) && !trait_exists($class, false)) { throw new ClassNotFoundException($class); } $classReflector = new \ReflectionClass($class);
switch ($class) { case 'ArrayIterator': case 'ArrayObject': $constructor = $classReflector->getConstructor()->invokeArgs(...);
return static function ($properties, $object) use ($constructor) { foreach ($properties as $name => &$value) { if ("\0" === $name) { $constructor($object, $value); } else { $object->$name = $value; $object->$name = &$value; } } }; }
if (!$classReflector->isInternal()) { $readonly = new \stdClass(); foreach ($classReflector->getProperties(\ReflectionProperty::IS_READONLY) as $propertyReflector) { if ($class === $propertyReflector->class) { $readonly->{$propertyReflector->name} = true; } }
return $baseHydrator->bindTo($readonly, $class); }
if ($classReflector->name !== $class) { return self::$simpleHydrators[$classReflector->name] ??= self::getSimpleHydrator($classReflector->name); }
$propertySetters = []; foreach ($classReflector->getProperties() as $propertyReflector) { if (!$propertyReflector->isStatic()) { $propertySetters[$propertyReflector->name] = $propertyReflector->setValue(...); } }
if (!$propertySetters) { return $baseHydrator; }
return static function ($properties, $object) use ($propertySetters) { foreach ($properties as $name => &$value) { if ($setValue = $propertySetters[$name] ?? null) { $setValue($object, $value); } else { $object->$name = $value; $object->$name = &$value; } } }; }
public static function getPropertyScopes($class): array { $propertyScopes = []; $r = new \ReflectionClass($class);
foreach ($r->getProperties() as $property) { $flags = $property->getModifiers();
if (\ReflectionProperty::IS_STATIC & $flags) { continue; } $name = $property->name;
if (\ReflectionProperty::IS_PRIVATE & $flags) { $readonlyScope = null; if ($flags & \ReflectionProperty::IS_READONLY) { $readonlyScope = $class; } $propertyScopes["\0$class\0$name"] = $propertyScopes[$name] = [$class, $name, $readonlyScope, $property];
continue; } $readonlyScope = null; if ($flags & \ReflectionProperty::IS_READONLY) { $readonlyScope = $property->class; } $propertyScopes[$name] = [$class, $name, $readonlyScope, $property];
if (\ReflectionProperty::IS_PROTECTED & $flags) { $propertyScopes["\0*\0$name"] = $propertyScopes[$name]; } }
while ($r = $r->getParentClass()) { $class = $r->name;
foreach ($r->getProperties(\ReflectionProperty::IS_PRIVATE) as $property) { if (!$property->isStatic()) { $name = $property->name; $readonlyScope = $property->isReadOnly() ? $class : null; $propertyScopes["\0$class\0$name"] = [$class, $name, $readonlyScope, $property]; $propertyScopes[$name] ??= [$class, $name, $readonlyScope, $property]; } } }
return $propertyScopes; } }
|