* * 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 * * @internal */ class Hydrator { public static $hydrators = []; public $registry; public $values; public $properties; public $value; public $wakeups; public function __construct(?Registry $registry, ?Values $values, array $properties, $value, array $wakeups) { $this->registry = $registry; $this->values = $values; $this->properties = $properties; $this->value = $value; $this->wakeups = $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) { switch ($class) { case 'stdClass': return self::$hydrators[$class] = static function ($properties, $objects) { foreach ($properties as $name => $values) { foreach ($values as $i => $v) { $objects[$i]->$name = $v; } } }; case 'ErrorException': return self::$hydrators[$class] = (self::$hydrators['stdClass'] ?? self::getHydrator('stdClass'))->bindTo(null, new class() extends \ErrorException { }); case 'TypeError': return self::$hydrators[$class] = (self::$hydrators['stdClass'] ?? self::getHydrator('stdClass'))->bindTo(null, new class() extends \Error { }); case 'SplObjectStorage': return self::$hydrators[$class] = 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 = \Closure::fromCallable([$classReflector->getConstructor(), 'invokeArgs']); return self::$hydrators[$class] = 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 self::$hydrators[$class] = (self::$hydrators['stdClass'] ?? self::getHydrator('stdClass'))->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()) { $propertyReflector->setAccessible(true); $propertySetters[$propertyReflector->name] = \Closure::fromCallable([$propertyReflector, 'setValue']); } } if (!$propertySetters) { return self::$hydrators[$class] = self::$hydrators['stdClass'] ?? self::getHydrator('stdClass'); } return self::$hydrators[$class] = 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; } } }; } }