Вход Регистрация
Файл: vendor/symfony/var-dumper/Cloner/Data.php
Строк: 347
<?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 SymfonyComponentVarDumperCloner;

use 
SymfonyComponentVarDumperCasterCaster;
use 
SymfonyComponentVarDumperDumperContextProviderSourceContextProvider;

/**
 * @author Nicolas Grekas <p@tchwork.com>
 */
class Data implements ArrayAccessCountableIteratorAggregateStringable
{
    private array 
$data;
    private 
int $position 0;
    private 
int|string $key 0;
    private 
int $maxDepth 20;
    private 
int $maxItemsPerDepth = -1;
    private 
int $useRefHandles = -1;
    private array 
$context = [];

    
/**
     * @param array $data An array as returned by ClonerInterface::cloneVar()
     */
    
public function __construct(array $data)
    {
        
$this->data $data;
    }

    public function 
getType(): ?string
    
{
        
$item $this->data[$this->position][$this->key];

        if (
$item instanceof Stub && Stub::TYPE_REF === $item->type && !$item->position) {
            
$item $item->value;
        }
        if (!
$item instanceof Stub) {
            return 
gettype($item);
        }
        if (
Stub::TYPE_STRING === $item->type) {
            return 
'string';
        }
        if (
Stub::TYPE_ARRAY === $item->type) {
            return 
'array';
        }
        if (
Stub::TYPE_OBJECT === $item->type) {
            return 
$item->class;
        }
        if (
Stub::TYPE_RESOURCE === $item->type) {
            return 
$item->class.' resource';
        }

        return 
null;
    }

    
/**
     * Returns a native representation of the original value.
     *
     * @param array|bool $recursive Whether values should be resolved recursively or not
     *
     * @return string|int|float|bool|array|Data[]|null
     */
    
public function getValue(array|bool $recursive false): string|int|float|bool|array|null
    
{
        
$item $this->data[$this->position][$this->key];

        if (
$item instanceof Stub && Stub::TYPE_REF === $item->type && !$item->position) {
            
$item $item->value;
        }
        if (!(
$item $this->getStub($item)) instanceof Stub) {
            return 
$item;
        }
        if (
Stub::TYPE_STRING === $item->type) {
            return 
$item->value;
        }

        
$children $item->position $this->data[$item->position] : [];

        foreach (
$children as $k => $v) {
            if (
$recursive && !($v $this->getStub($v)) instanceof Stub) {
                continue;
            }
            
$children[$k] = clone $this;
            
$children[$k]->key $k;
            
$children[$k]->position $item->position;

            if (
$recursive) {
                if (
Stub::TYPE_REF === $v->type && ($v $this->getStub($v->value)) instanceof Stub) {
                    
$recursive = (array) $recursive;
                    if (isset(
$recursive[$v->position])) {
                        continue;
                    }
                    
$recursive[$v->position] = true;
                }
                
$children[$k] = $children[$k]->getValue($recursive);
            }
        }

        return 
$children;
    }

    public function 
count(): int
    
{
        return 
count($this->getValue());
    }

    public function 
getIterator(): Traversable
    
{
        if (!
is_array($value $this->getValue())) {
            throw new 
LogicException(sprintf('"%s" object holds non-iterable type "%s".'self::class, get_debug_type($value)));
        }

        yield from 
$value;
    }

    
/**
     * @return mixed
     */
    
public function __get(string $key)
    {
        if (
null !== $data $this->seek($key)) {
            
$item $this->getStub($data->data[$data->position][$data->key]);

            return 
$item instanceof Stub || [] === $item $data $item;
        }

        return 
null;
    }

    public function 
__isset(string $key): bool
    
{
        return 
null !== $this->seek($key);
    }

    public function 
offsetExists(mixed $key): bool
    
{
        return 
$this->__isset($key);
    }

    public function 
offsetGet(mixed $key): mixed
    
{
        return 
$this->__get($key);
    }

    public function 
offsetSet(mixed $keymixed $value): void
    
{
        throw new 
BadMethodCallException(self::class.' objects are immutable.');
    }

    public function 
offsetUnset(mixed $key): void
    
{
        throw new 
BadMethodCallException(self::class.' objects are immutable.');
    }

    public function 
__toString(): string
    
{
        
$value $this->getValue();

        if (!
is_array($value)) {
            return (string) 
$value;
        }

        return 
sprintf('%s (count=%d)'$this->getType(), count($value));
    }

    
/**
     * Returns a depth limited clone of $this.
     */
    
public function withMaxDepth(int $maxDepth): static
    {
        
$data = clone $this;
        
$data->maxDepth $maxDepth;

        return 
$data;
    }

    
/**
     * Limits the number of elements per depth level.
     */
    
public function withMaxItemsPerDepth(int $maxItemsPerDepth): static
    {
        
$data = clone $this;
        
$data->maxItemsPerDepth $maxItemsPerDepth;

        return 
$data;
    }

    
/**
     * Enables/disables objects' identifiers tracking.
     *
     * @param bool $useRefHandles False to hide global ref. handles
     */
    
public function withRefHandles(bool $useRefHandles): static
    {
        
$data = clone $this;
        
$data->useRefHandles $useRefHandles ? -0;

        return 
$data;
    }

    public function 
withContext(array $context): static
    {
        
$data = clone $this;
        
$data->context $context;

        return 
$data;
    }

    public function 
getContext(): array
    {
        return 
$this->context;
    }

    
/**
     * Seeks to a specific key in nested data structures.
     */
    
public function seek(string|int $key): ?static
    {
        
$item $this->data[$this->position][$this->key];

        if (
$item instanceof Stub && Stub::TYPE_REF === $item->type && !$item->position) {
            
$item $item->value;
        }
        if (!(
$item $this->getStub($item)) instanceof Stub || !$item->position) {
            return 
null;
        }
        
$keys = [$key];

        switch (
$item->type) {
            case 
Stub::TYPE_OBJECT:
                
$keys[] = Caster::PREFIX_DYNAMIC.$key;
                
$keys[] = Caster::PREFIX_PROTECTED.$key;
                
$keys[] = Caster::PREFIX_VIRTUAL.$key;
                
$keys[] = "$item->class$key";
                
// no break
            
case Stub::TYPE_ARRAY:
            case 
Stub::TYPE_RESOURCE:
                break;
            default:
                return 
null;
        }

        
$data null;
        
$children $this->data[$item->position];

        foreach (
$keys as $key) {
            if (isset(
$children[$key]) || array_key_exists($key$children)) {
                
$data = clone $this;
                
$data->key $key;
                
$data->position $item->position;
                break;
            }
        }

        return 
$data;
    }

    
/**
     * Dumps data with a DumperInterface dumper.
     *
     * @return void
     */
    
public function dump(DumperInterface $dumper)
    {
        
$refs = [0];
        
$cursor = new Cursor();
        
$cursor->hashType = -1;
        
$cursor->attr $this->context[SourceContextProvider::class] ?? [];
        
$label $this->context['label'] ?? '';

        if (
$cursor->attr || '' !== $label) {
            
$dumper->dumpScalar($cursor'label'$label);
        }
        
$cursor->hashType 0;
        
$this->dumpItem($dumper$cursor$refs$this->data[$this->position][$this->key]);
    }

    
/**
     * Depth-first dumping of items.
     *
     * @param mixed $item A Stub object or the original value being dumped
     */
    
private function dumpItem(DumperInterface $dumperCursor $cursor, array &$refsmixed $item): void
    
{
        
$cursor->refIndex 0;
        
$cursor->softRefTo $cursor->softRefHandle $cursor->softRefCount 0;
        
$cursor->hardRefTo $cursor->hardRefHandle $cursor->hardRefCount 0;
        
$firstSeen true;

        if (!
$item instanceof Stub) {
            
$cursor->attr = [];
            
$type gettype($item);
            if (
$item && 'array' === $type) {
                
$item $this->getStub($item);
            }
        } elseif (
Stub::TYPE_REF === $item->type) {
            if (
$item->handle) {
                if (!isset(
$refs[$r $item->handle - (PHP_INT_MAX >> 1)])) {
                    
$cursor->refIndex $refs[$r] = $cursor->refIndex ?: ++$refs[0];
                } else {
                    
$firstSeen false;
                }
                
$cursor->hardRefTo $refs[$r];
                
$cursor->hardRefHandle $this->useRefHandles $item->handle;
                
$cursor->hardRefCount $item->handle $item->refCount 0;
            }
            
$cursor->attr $item->attr;
            
$type $item->class ?: gettype($item->value);
            
$item $this->getStub($item->value);
        }
        if (
$item instanceof Stub) {
            if (
$item->refCount) {
                if (!isset(
$refs[$r $item->handle])) {
                    
$cursor->refIndex $refs[$r] = $cursor->refIndex ?: ++$refs[0];
                } else {
                    
$firstSeen false;
                }
                
$cursor->softRefTo $refs[$r];
            }
            
$cursor->softRefHandle $this->useRefHandles $item->handle;
            
$cursor->softRefCount $item->refCount;
            
$cursor->attr $item->attr;
            
$cut $item->cut;

            if (
$item->position && $firstSeen) {
                
$children $this->data[$item->position];

                if (
$cursor->stop) {
                    if (
$cut >= 0) {
                        
$cut += count($children);
                    }
                    
$children = [];
                }
            } else {
                
$children = [];
            }
            switch (
$item->type) {
                case 
Stub::TYPE_STRING:
                    
$dumper->dumpString($cursor$item->valueStub::STRING_BINARY === $item->class$cut);
                    break;

                case 
Stub::TYPE_ARRAY:
                    
$item = clone $item;
                    
$item->type $item->class;
                    
$item->class $item->value;
                    
// no break
                
case Stub::TYPE_OBJECT:
                case 
Stub::TYPE_RESOURCE:
                    
$withChildren $children && $cursor->depth !== $this->maxDepth && $this->maxItemsPerDepth;
                    
$dumper->enterHash($cursor$item->type$item->class$withChildren);
                    if (
$withChildren) {
                        if (
$cursor->skipChildren) {
                            
$withChildren false;
                            
$cut = -1;
                        } else {
                            
$cut $this->dumpChildren($dumper$cursor$refs$children$cut$item->typenull !== $item->class);
                        }
                    } elseif (
$children && <= $cut) {
                        
$cut += count($children);
                    }
                    
$cursor->skipChildren false;
                    
$dumper->leaveHash($cursor$item->type$item->class$withChildren$cut);
                    break;

                case 
Stub::TYPE_SCALAR:
                    
$dumper->dumpScalar($cursor'default'$item->attr['value']);
                    break;

                default:
                    throw new 
RuntimeException(sprintf('Unexpected Stub type: "%s".'$item->type));
            }
        } elseif (
'array' === $type) {
            
$dumper->enterHash($cursorCursor::HASH_INDEXED0false);
            
$dumper->leaveHash($cursorCursor::HASH_INDEXED0false0);
        } elseif (
'string' === $type) {
            
$dumper->dumpString($cursor$itemfalse0);
        } else {
            
$dumper->dumpScalar($cursor$type$item);
        }
    }

    
/**
     * Dumps children of hash structures.
     *
     * @return int The final number of removed items
     */
    
private function dumpChildren(DumperInterface $dumperCursor $parentCursor, array &$refs, array $childrenint $hashCutint $hashTypebool $dumpKeys): int
    
{
        
$cursor = clone $parentCursor;
        ++
$cursor->depth;
        
$cursor->hashType $hashType;
        
$cursor->hashIndex 0;
        
$cursor->hashLength count($children);
        
$cursor->hashCut $hashCut;
        foreach (
$children as $key => $child) {
            
$cursor->hashKeyIsBinary = isset($key[0]) && !preg_match('//u'$key);
            
$cursor->hashKey $dumpKeys $key null;
            
$this->dumpItem($dumper$cursor$refs$child);
            if (++
$cursor->hashIndex === $this->maxItemsPerDepth || $cursor->stop) {
                
$parentCursor->stop true;

                return 
$hashCut >= $hashCut $cursor->hashLength $cursor->hashIndex $hashCut;
            }
        }

        return 
$hashCut;
    }

    private function 
getStub(mixed $item): mixed
    
{
        if (!
$item || !is_array($item)) {
            return 
$item;
        }

        
$stub = new Stub();
        
$stub->type Stub::TYPE_ARRAY;
        foreach (
$item as $stub->class => $stub->position) {
        }
        if (isset(
$item[0])) {
            
$stub->cut $item[0];
        }
        
$stub->value $stub->cut + ($stub->position count($this->data[$stub->position]) : 0);

        return 
$stub;
    }
}
Онлайн: 3
Реклама