Skip to main content
Drupal API
User account menu
  • Log in

Breadcrumb

  1. Drupal Core 11.1.x
  2. Exporter.php

function Exporter::prepare

Prepares an array of values for VarExporter.

For performance this method is public and has no type-hints.

Parameters

array &$values:

\SplObjectStorage $objectsPool:

array &$refsPool:

int &$objectsCount:

bool &$valuesAreStatic:

Return value

array

Throws

NotInstantiableTypeException When a value cannot be serialized

File

vendor/symfony/var-exporter/Internal/Exporter.php, line 38

Class

Exporter
@author Nicolas Grekas <p@tchwork.com>

Namespace

Symfony\Component\VarExporter\Internal

Code

public static function prepare($values, $objectsPool, &$refsPool, &$objectsCount, &$valuesAreStatic) {
    $refs = $values;
    foreach ($values as $k => $value) {
        if (\is_resource($value)) {
            throw new NotInstantiableTypeException(get_resource_type($value) . ' resource');
        }
        $refs[$k] = $objectsPool;
        if ($isRef = !($valueIsStatic = $values[$k] !== $objectsPool)) {
            $values[$k] =& $value;
            // Break hard references to make $values completely
            unset($value);
            // independent from the original structure
            $refs[$k] = $value = $values[$k];
            if ($value instanceof Reference && 0 > $value->id) {
                $valuesAreStatic = false;
                ++$value->count;
                continue;
            }
            $refsPool[] = [
                &$refs[$k],
                $value,
                &$value,
            ];
            $refs[$k] = $values[$k] = new Reference(-\count($refsPool), $value);
        }
        if (\is_array($value)) {
            if ($value) {
                $value = self::prepare($value, $objectsPool, $refsPool, $objectsCount, $valueIsStatic);
            }
            goto handle_value;
        }
        elseif (!\is_object($value) || $value instanceof \UnitEnum) {
            goto handle_value;
        }
        $valueIsStatic = false;
        if (isset($objectsPool[$value])) {
            ++$objectsCount;
            $value = new Reference($objectsPool[$value][0]);
            goto handle_value;
        }
        $class = $value::class;
        $reflector = Registry::$reflectors[$class] ??= Registry::getClassReflector($class);
        $properties = [];
        if ($reflector->hasMethod('__serialize')) {
            if (!$reflector->getMethod('__serialize')
                ->isPublic()) {
                throw new \Error(\sprintf('Call to %s method "%s::__serialize()".', $reflector->getMethod('__serialize')
                    ->isProtected() ? 'protected' : 'private', $class));
            }
            if (!\is_array($serializeProperties = $value->__serialize())) {
                throw new \TypeError($class . '::__serialize() must return an array');
            }
            if ($reflector->hasMethod('__unserialize')) {
                $properties = $serializeProperties;
            }
            else {
                foreach ($serializeProperties as $n => $v) {
                    $c = $reflector->hasProperty($n) && ($p = $reflector->getProperty($n))
                        ->isReadOnly() ? $p->class : 'stdClass';
                    $properties[$c][$n] = $v;
                }
            }
            goto prepare_value;
        }
        $sleep = null;
        $proto = Registry::$prototypes[$class];
        if (($value instanceof \ArrayIterator || $value instanceof \ArrayObject) && null !== $proto) {
            // ArrayIterator and ArrayObject need special care because their "flags"
            // option changes the behavior of the (array) casting operator.
            [
                $arrayValue,
                $properties,
            ] = self::getArrayObjectProperties($value, $proto);
            // populates Registry::$prototypes[$class] with a new instance
            Registry::getClassReflector($class, Registry::$instantiableWithoutConstructor[$class], Registry::$cloneable[$class]);
        }
        elseif ($value instanceof \SplObjectStorage && Registry::$cloneable[$class] && null !== $proto) {
            // By implementing Serializable, SplObjectStorage breaks
            // internal references; let's deal with it on our own.
            foreach (clone $value as $v) {
                $properties[] = $v;
                $properties[] = $value[$v];
            }
            $properties = [
                'SplObjectStorage' => [
                    "\x00" => $properties,
                ],
            ];
            $arrayValue = (array) $value;
        }
        elseif ($value instanceof \Serializable || $value instanceof \__PHP_Incomplete_Class) {
            ++$objectsCount;
            $objectsPool[$value] = [
                $id = \count($objectsPool),
                serialize($value),
                [],
                0,
            ];
            $value = new Reference($id);
            goto handle_value;
        }
        else {
            if (method_exists($class, '__sleep')) {
                if (!\is_array($sleep = $value->__sleep())) {
                    trigger_error('serialize(): __sleep should return an array only containing the names of instance-variables to serialize', \E_USER_NOTICE);
                    $value = null;
                    goto handle_value;
                }
                $sleep = array_flip($sleep);
            }
            $arrayValue = (array) $value;
        }
        $proto = (array) $proto;
        foreach ($arrayValue as $name => $v) {
            $i = 0;
            $n = (string) $name;
            if ('' === $n || "\x00" !== $n[0]) {
                $c = $reflector->hasProperty($n) && ($p = $reflector->getProperty($n))
                    ->isReadOnly() ? $p->class : 'stdClass';
            }
            elseif ('*' === $n[1]) {
                $n = substr($n, 3);
                $c = $reflector->getProperty($n)->class;
                if ('Error' === $c) {
                    $c = 'TypeError';
                }
                elseif ('Exception' === $c) {
                    $c = 'ErrorException';
                }
            }
            else {
                $i = strpos($n, "\x00", 2);
                $c = substr($n, 1, $i - 1);
                $n = substr($n, 1 + $i);
            }
            if (null !== $sleep) {
                if (!isset($sleep[$name]) && (!isset($sleep[$n]) || $i && $c !== $class)) {
                    unset($arrayValue[$name]);
                    continue;
                }
                unset($sleep[$name], $sleep[$n]);
            }
            if (!\array_key_exists($name, $proto) || $proto[$name] !== $v || "\x00Error\x00trace" === $name || "\x00Exception\x00trace" === $name) {
                $properties[$c][$n] = $v;
            }
        }
        if ($sleep) {
            foreach ($sleep as $n => $v) {
                trigger_error(\sprintf('serialize(): "%s" returned as member variable from __sleep() but does not exist', $n), \E_USER_NOTICE);
            }
        }
        if (method_exists($class, '__unserialize')) {
            $properties = $arrayValue;
        }
        prepare_value:
        $objectsPool[$value] = [
            $id = \count($objectsPool),
        ];
        $properties = self::prepare($properties, $objectsPool, $refsPool, $objectsCount, $valueIsStatic);
        ++$objectsCount;
        $objectsPool[$value] = [
            $id,
            $class,
            $properties,
            method_exists($class, '__unserialize') ? -$objectsCount : (method_exists($class, '__wakeup') ? $objectsCount : 0),
        ];
        $value = new Reference($id);
        handle_value:
        if ($isRef) {
            unset($value);
            // Break the hard reference created above
        }
        elseif (!$valueIsStatic) {
            $values[$k] = $value;
        }
        $valuesAreStatic = $valueIsStatic && $valuesAreStatic;
    }
    return $values;
}
RSS feed
Powered by Drupal