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

/**
 * AbstractCloner implements a generic caster mechanism for objects and resources.
 *
 * @author Nicolas Grekas <p@tchwork.com>
 */
abstract class AbstractCloner implements ClonerInterface
{
    public static array 
$defaultCasters = [
        
'__PHP_Incomplete_Class' => ['SymfonyComponentVarDumperCasterCaster', 'castPhpIncompleteClass'],

        
'AddressInfo' => ['SymfonyComponentVarDumperCasterAddressInfoCaster', 'castAddressInfo'],
        
'Socket' => ['SymfonyComponentVarDumperCasterSocketCaster', 'castSocket'],

        
'SymfonyComponentVarDumperCasterCutStub' => ['SymfonyComponentVarDumperCasterStubCaster', 'castStub'],
        
'SymfonyComponentVarDumperCasterCutArrayStub' => ['SymfonyComponentVarDumperCasterStubCaster', 'castCutArray'],
        
'SymfonyComponentVarDumperCasterConstStub' => ['SymfonyComponentVarDumperCasterStubCaster', 'castStub'],
        
'SymfonyComponentVarDumperCasterEnumStub' => ['SymfonyComponentVarDumperCasterStubCaster', 'castEnum'],
        
'SymfonyComponentVarDumperCasterScalarStub' => ['SymfonyComponentVarDumperCasterStubCaster', 'castScalar'],

        
'Fiber' => ['SymfonyComponentVarDumperCasterFiberCaster', 'castFiber'],

        
'Closure' => ['SymfonyComponentVarDumperCasterReflectionCaster', 'castClosure'],
        
'Generator' => ['SymfonyComponentVarDumperCasterReflectionCaster', 'castGenerator'],
        
'ReflectionType' => ['SymfonyComponentVarDumperCasterReflectionCaster', 'castType'],
        
'ReflectionAttribute' => ['SymfonyComponentVarDumperCasterReflectionCaster', 'castAttribute'],
        
'ReflectionGenerator' => ['SymfonyComponentVarDumperCasterReflectionCaster', 'castReflectionGenerator'],
        
'ReflectionClass' => ['SymfonyComponentVarDumperCasterReflectionCaster', 'castClass'],
        
'ReflectionClassConstant' => ['SymfonyComponentVarDumperCasterReflectionCaster', 'castClassConstant'],
        
'ReflectionFunctionAbstract' => ['SymfonyComponentVarDumperCasterReflectionCaster', 'castFunctionAbstract'],
        
'ReflectionMethod' => ['SymfonyComponentVarDumperCasterReflectionCaster', 'castMethod'],
        
'ReflectionParameter' => ['SymfonyComponentVarDumperCasterReflectionCaster', 'castParameter'],
        
'ReflectionProperty' => ['SymfonyComponentVarDumperCasterReflectionCaster', 'castProperty'],
        
'ReflectionReference' => ['SymfonyComponentVarDumperCasterReflectionCaster', 'castReference'],
        
'ReflectionExtension' => ['SymfonyComponentVarDumperCasterReflectionCaster', 'castExtension'],
        
'ReflectionZendExtension' => ['SymfonyComponentVarDumperCasterReflectionCaster', 'castZendExtension'],

        
'DoctrineCommonPersistenceObjectManager' => ['SymfonyComponentVarDumperCasterStubCaster', 'cutInternals'],
        
'DoctrineCommonProxyProxy' => ['SymfonyComponentVarDumperCasterDoctrineCaster', 'castCommonProxy'],
        
'DoctrineORMProxyProxy' => ['SymfonyComponentVarDumperCasterDoctrineCaster', 'castOrmProxy'],
        
'DoctrineORMPersistentCollection' => ['SymfonyComponentVarDumperCasterDoctrineCaster', 'castPersistentCollection'],
        
'DoctrinePersistenceObjectManager' => ['SymfonyComponentVarDumperCasterStubCaster', 'cutInternals'],

        
'DOMException' => ['SymfonyComponentVarDumperCasterDOMCaster', 'castException'],
        
'DomException' => ['SymfonyComponentVarDumperCasterDOMCaster', 'castException'],
        
'DOMStringList' => ['SymfonyComponentVarDumperCasterDOMCaster', 'castDom'],
        
'DOMNameList' => ['SymfonyComponentVarDumperCasterDOMCaster', 'castDom'],
        
'DOMImplementation' => ['SymfonyComponentVarDumperCasterDOMCaster', 'castImplementation'],
        
'DomImplementation' => ['SymfonyComponentVarDumperCasterDOMCaster', 'castImplementation'],
        
'DOMImplementationList' => ['SymfonyComponentVarDumperCasterDOMCaster', 'castDom'],
        
'DOMNode' => ['SymfonyComponentVarDumperCasterDOMCaster', 'castDom'],
        
'DomNode' => ['SymfonyComponentVarDumperCasterDOMCaster', 'castDom'],
        
'DOMNameSpaceNode' => ['SymfonyComponentVarDumperCasterDOMCaster', 'castDom'],
        
'DOMDocument' => ['SymfonyComponentVarDumperCasterDOMCaster', 'castDocument'],
        
'DomXMLDocument' => ['SymfonyComponentVarDumperCasterDOMCaster', 'castXMLDocument'],
        
'DomHTMLDocument' => ['SymfonyComponentVarDumperCasterDOMCaster', 'castHTMLDocument'],
        
'DOMNodeList' => ['SymfonyComponentVarDumperCasterDOMCaster', 'castDom'],
        
'DomNodeList' => ['SymfonyComponentVarDumperCasterDOMCaster', 'castDom'],
        
'DOMNamedNodeMap' => ['SymfonyComponentVarDumperCasterDOMCaster', 'castDom'],
        
'DomDTDNamedNodeMap' => ['SymfonyComponentVarDumperCasterDOMCaster', 'castDom'],
        
'DOMXPath' => ['SymfonyComponentVarDumperCasterDOMCaster', 'castDom'],
        
'DomXPath' => ['SymfonyComponentVarDumperCasterDOMCaster', 'castDom'],
        
'DomHTMLCollection' => ['SymfonyComponentVarDumperCasterDOMCaster', 'castDom'],
        
'DomTokenList' => ['SymfonyComponentVarDumperCasterDOMCaster', 'castDom'],

        
'XMLReader' => ['SymfonyComponentVarDumperCasterXmlReaderCaster', 'castXmlReader'],

        
'ErrorException' => ['SymfonyComponentVarDumperCasterExceptionCaster', 'castErrorException'],
        
'Exception' => ['SymfonyComponentVarDumperCasterExceptionCaster', 'castException'],
        
'Error' => ['SymfonyComponentVarDumperCasterExceptionCaster', 'castError'],
        
'SymfonyBridgeMonologLogger' => ['SymfonyComponentVarDumperCasterStubCaster', 'cutInternals'],
        
'SymfonyComponentDependencyInjectionContainerInterface' => ['SymfonyComponentVarDumperCasterStubCaster', 'cutInternals'],
        
'SymfonyComponentEventDispatcherEventDispatcherInterface' => ['SymfonyComponentVarDumperCasterStubCaster', 'cutInternals'],
        
'SymfonyComponentHttpClientAmpHttpClient' => ['SymfonyComponentVarDumperCasterSymfonyCaster', 'castHttpClient'],
        
'SymfonyComponentHttpClientCurlHttpClient' => ['SymfonyComponentVarDumperCasterSymfonyCaster', 'castHttpClient'],
        
'SymfonyComponentHttpClientNativeHttpClient' => ['SymfonyComponentVarDumperCasterSymfonyCaster', 'castHttpClient'],
        
'SymfonyComponentHttpClientResponseAmpResponse' => ['SymfonyComponentVarDumperCasterSymfonyCaster', 'castHttpClientResponse'],
        
'SymfonyComponentHttpClientResponseAmpResponseV4' => ['SymfonyComponentVarDumperCasterSymfonyCaster', 'castHttpClientResponse'],
        
'SymfonyComponentHttpClientResponseAmpResponseV5' => ['SymfonyComponentVarDumperCasterSymfonyCaster', 'castHttpClientResponse'],
        
'SymfonyComponentHttpClientResponseCurlResponse' => ['SymfonyComponentVarDumperCasterSymfonyCaster', 'castHttpClientResponse'],
        
'SymfonyComponentHttpClientResponseNativeResponse' => ['SymfonyComponentVarDumperCasterSymfonyCaster', 'castHttpClientResponse'],
        
'SymfonyComponentHttpFoundationRequest' => ['SymfonyComponentVarDumperCasterSymfonyCaster', 'castRequest'],
        
'SymfonyComponentUidUlid' => ['SymfonyComponentVarDumperCasterSymfonyCaster', 'castUlid'],
        
'SymfonyComponentUidUuid' => ['SymfonyComponentVarDumperCasterSymfonyCaster', 'castUuid'],
        
'SymfonyComponentVarExporterInternalLazyObjectState' => ['SymfonyComponentVarDumperCasterSymfonyCaster', 'castLazyObjectState'],
        
'SymfonyComponentVarDumperExceptionThrowingCasterException' => ['SymfonyComponentVarDumperCasterExceptionCaster', 'castThrowingCasterException'],
        
'SymfonyComponentVarDumperCasterTraceStub' => ['SymfonyComponentVarDumperCasterExceptionCaster', 'castTraceStub'],
        
'SymfonyComponentVarDumperCasterFrameStub' => ['SymfonyComponentVarDumperCasterExceptionCaster', 'castFrameStub'],
        
'SymfonyComponentVarDumperClonerAbstractCloner' => ['SymfonyComponentVarDumperCasterStubCaster', 'cutInternals'],
        
'SymfonyComponentErrorHandlerExceptionFlattenException' => ['SymfonyComponentVarDumperCasterExceptionCaster', 'castFlattenException'],
        
'SymfonyComponentErrorHandlerExceptionSilencedErrorContext' => ['SymfonyComponentVarDumperCasterExceptionCaster', 'castSilencedErrorContext'],

        
'ImagineImageImageInterface' => ['SymfonyComponentVarDumperCasterImagineCaster', 'castImage'],

        
'RamseyUuidUuidInterface' => ['SymfonyComponentVarDumperCasterUuidCaster', 'castRamseyUuid'],

        
'ProxyManagerProxyProxyInterface' => ['SymfonyComponentVarDumperCasterProxyManagerCaster', 'castProxy'],
        
'PHPUnit_Framework_MockObject_MockObject' => ['SymfonyComponentVarDumperCasterStubCaster', 'cutInternals'],
        
'PHPUnitFrameworkMockObjectMockObject' => ['SymfonyComponentVarDumperCasterStubCaster', 'cutInternals'],
        
'PHPUnitFrameworkMockObjectStub' => ['SymfonyComponentVarDumperCasterStubCaster', 'cutInternals'],
        
'ProphecyProphecyProphecySubjectInterface' => ['SymfonyComponentVarDumperCasterStubCaster', 'cutInternals'],
        
'MockeryMockInterface' => ['SymfonyComponentVarDumperCasterStubCaster', 'cutInternals'],

        
'PDO' => ['SymfonyComponentVarDumperCasterPdoCaster', 'castPdo'],
        
'PDOStatement' => ['SymfonyComponentVarDumperCasterPdoCaster', 'castPdoStatement'],

        
'AMQPConnection' => ['SymfonyComponentVarDumperCasterAmqpCaster', 'castConnection'],
        
'AMQPChannel' => ['SymfonyComponentVarDumperCasterAmqpCaster', 'castChannel'],
        
'AMQPQueue' => ['SymfonyComponentVarDumperCasterAmqpCaster', 'castQueue'],
        
'AMQPExchange' => ['SymfonyComponentVarDumperCasterAmqpCaster', 'castExchange'],
        
'AMQPEnvelope' => ['SymfonyComponentVarDumperCasterAmqpCaster', 'castEnvelope'],

        
'ArrayObject' => ['SymfonyComponentVarDumperCasterSplCaster', 'castArrayObject'],
        
'ArrayIterator' => ['SymfonyComponentVarDumperCasterSplCaster', 'castArrayIterator'],
        
'SplDoublyLinkedList' => ['SymfonyComponentVarDumperCasterSplCaster', 'castDoublyLinkedList'],
        
'SplFileInfo' => ['SymfonyComponentVarDumperCasterSplCaster', 'castFileInfo'],
        
'SplFileObject' => ['SymfonyComponentVarDumperCasterSplCaster', 'castFileObject'],
        
'SplHeap' => ['SymfonyComponentVarDumperCasterSplCaster', 'castHeap'],
        
'SplObjectStorage' => ['SymfonyComponentVarDumperCasterSplCaster', 'castObjectStorage'],
        
'SplPriorityQueue' => ['SymfonyComponentVarDumperCasterSplCaster', 'castHeap'],
        
'OuterIterator' => ['SymfonyComponentVarDumperCasterSplCaster', 'castOuterIterator'],
        
'WeakMap' => ['SymfonyComponentVarDumperCasterSplCaster', 'castWeakMap'],
        
'WeakReference' => ['SymfonyComponentVarDumperCasterSplCaster', 'castWeakReference'],

        
'Redis' => ['SymfonyComponentVarDumperCasterRedisCaster', 'castRedis'],
        
'RelayRelay' => ['SymfonyComponentVarDumperCasterRedisCaster', 'castRedis'],
        
'RedisArray' => ['SymfonyComponentVarDumperCasterRedisCaster', 'castRedisArray'],
        
'RedisCluster' => ['SymfonyComponentVarDumperCasterRedisCaster', 'castRedisCluster'],

        
'DateTimeInterface' => ['SymfonyComponentVarDumperCasterDateCaster', 'castDateTime'],
        
'DateInterval' => ['SymfonyComponentVarDumperCasterDateCaster', 'castInterval'],
        
'DateTimeZone' => ['SymfonyComponentVarDumperCasterDateCaster', 'castTimeZone'],
        
'DatePeriod' => ['SymfonyComponentVarDumperCasterDateCaster', 'castPeriod'],

        
'GMP' => ['SymfonyComponentVarDumperCasterGmpCaster', 'castGmp'],

        
'MessageFormatter' => ['SymfonyComponentVarDumperCasterIntlCaster', 'castMessageFormatter'],
        
'NumberFormatter' => ['SymfonyComponentVarDumperCasterIntlCaster', 'castNumberFormatter'],
        
'IntlTimeZone' => ['SymfonyComponentVarDumperCasterIntlCaster', 'castIntlTimeZone'],
        
'IntlCalendar' => ['SymfonyComponentVarDumperCasterIntlCaster', 'castIntlCalendar'],
        
'IntlDateFormatter' => ['SymfonyComponentVarDumperCasterIntlCaster', 'castIntlDateFormatter'],

        
'Memcached' => ['SymfonyComponentVarDumperCasterMemcachedCaster', 'castMemcached'],

        
'DsCollection' => ['SymfonyComponentVarDumperCasterDsCaster', 'castCollection'],
        
'DsMap' => ['SymfonyComponentVarDumperCasterDsCaster', 'castMap'],
        
'DsPair' => ['SymfonyComponentVarDumperCasterDsCaster', 'castPair'],
        
'SymfonyComponentVarDumperCasterDsPairStub' => ['SymfonyComponentVarDumperCasterDsCaster', 'castPairStub'],

        
'mysqli_driver' => ['SymfonyComponentVarDumperCasterMysqliCaster', 'castMysqliDriver'],

        
'CurlHandle' => ['SymfonyComponentVarDumperCasterCurlCaster', 'castCurl'],

        
'DbaConnection' => ['SymfonyComponentVarDumperCasterResourceCaster', 'castDba'],
        
':dba' => ['SymfonyComponentVarDumperCasterResourceCaster', 'castDba'],
        
':dba persistent' => ['SymfonyComponentVarDumperCasterResourceCaster', 'castDba'],

        
'GdImage' => ['SymfonyComponentVarDumperCasterGdCaster', 'castGd'],

        
'SQLite3Result' => ['SymfonyComponentVarDumperCasterSqliteCaster', 'castSqlite3Result'],

        
'PgSqlLob' => ['SymfonyComponentVarDumperCasterPgSqlCaster', 'castLargeObject'],
        
'PgSqlConnection' => ['SymfonyComponentVarDumperCasterPgSqlCaster', 'castLink'],
        
'PgSqlResult' => ['SymfonyComponentVarDumperCasterPgSqlCaster', 'castResult'],

        
':process' => ['SymfonyComponentVarDumperCasterResourceCaster', 'castProcess'],
        
':stream' => ['SymfonyComponentVarDumperCasterResourceCaster', 'castStream'],

        
'OpenSSLAsymmetricKey' => ['SymfonyComponentVarDumperCasterOpenSSLCaster', 'castOpensslAsymmetricKey'],
        
'OpenSSLCertificateSigningRequest' => ['SymfonyComponentVarDumperCasterOpenSSLCaster', 'castOpensslCsr'],
        
'OpenSSLCertificate' => ['SymfonyComponentVarDumperCasterOpenSSLCaster', 'castOpensslX509'],

        
':persistent stream' => ['SymfonyComponentVarDumperCasterResourceCaster', 'castStream'],
        
':stream-context' => ['SymfonyComponentVarDumperCasterResourceCaster', 'castStreamContext'],

        
'XmlParser' => ['SymfonyComponentVarDumperCasterXmlResourceCaster', 'castXml'],

        
'RdKafka' => ['SymfonyComponentVarDumperCasterRdKafkaCaster', 'castRdKafka'],
        
'RdKafkaConf' => ['SymfonyComponentVarDumperCasterRdKafkaCaster', 'castConf'],
        
'RdKafkaKafkaConsumer' => ['SymfonyComponentVarDumperCasterRdKafkaCaster', 'castKafkaConsumer'],
        
'RdKafkaMetadataBroker' => ['SymfonyComponentVarDumperCasterRdKafkaCaster', 'castBrokerMetadata'],
        
'RdKafkaMetadataCollection' => ['SymfonyComponentVarDumperCasterRdKafkaCaster', 'castCollectionMetadata'],
        
'RdKafkaMetadataPartition' => ['SymfonyComponentVarDumperCasterRdKafkaCaster', 'castPartitionMetadata'],
        
'RdKafkaMetadataTopic' => ['SymfonyComponentVarDumperCasterRdKafkaCaster', 'castTopicMetadata'],
        
'RdKafkaMessage' => ['SymfonyComponentVarDumperCasterRdKafkaCaster', 'castMessage'],
        
'RdKafkaTopic' => ['SymfonyComponentVarDumperCasterRdKafkaCaster', 'castTopic'],
        
'RdKafkaTopicPartition' => ['SymfonyComponentVarDumperCasterRdKafkaCaster', 'castTopicPartition'],
        
'RdKafkaTopicConf' => ['SymfonyComponentVarDumperCasterRdKafkaCaster', 'castTopicConf'],

        
'FFICData' => ['SymfonyComponentVarDumperCasterFFICaster', 'castCTypeOrCData'],
        
'FFICType' => ['SymfonyComponentVarDumperCasterFFICaster', 'castCTypeOrCData'],
    ];

    protected 
int $maxItems = 2500;
    protected 
int $maxString = -1;
    protected 
int $minDepth = 1;

    
/**
     * @var array<string, list<callable>>
     */
    
private array $casters = [];

    
/**
     * @var callable|null
     */
    
private $prevErrorHandler;

    private array 
$classInfo = [];
    private 
int $filter = 0;

    
/**
     * @param callable[]|null $casters A map of casters
     *
     * @see addCasters
     */
    
public function __construct(?array $casters = null)
    {
        
$this->addCasters($casters ?? static::$defaultCasters);
    }

    
/**
     * Adds casters for resources and objects.
     *
     * Maps resources or object types to a callback.
     * Use types as keys and callable casters as values.
     * Prefix types with `::`,
     * see e.g. self::$defaultCasters.
     *
     * @param array<string, callable> $casters A map of casters
     */
    
public function addCasters(array $casters): void
    
{
        foreach (
$casters as $type => $callback) {
            
$this->casters[$type][] = $callback;
        }
    }

    
/**
     * Adds default casters for resources and objects.
     *
     * Maps resources or object types to a callback.
     * Use types as keys and callable casters as values.
     * Prefix types with `::`,
     * see e.g. self::$defaultCasters.
     *
     * @param array<string, callable> $casters A map of casters
     */
    
public static function addDefaultCasters(array $casters): void
    
{
        
self::$defaultCasters = [...self::$defaultCasters, ...$casters];
    }

    
/**
     * Sets the maximum number of items to clone past the minimum depth in nested structures.
     */
    
public function setMaxItems(int $maxItems): void
    
{
        
$this->maxItems = $maxItems;
    }

    
/**
     * Sets the maximum cloned length for strings.
     */
    
public function setMaxString(int $maxString): void
    
{
        
$this->maxString = $maxString;
    }

    
/**
     * Sets the minimum tree depth where we are guaranteed to clone all the items.  After this
     * depth is reached, only setMaxItems items will be cloned.
     */
    
public function setMinDepth(int $minDepth): void
    
{
        
$this->minDepth = $minDepth;
    }

    
/**
     * Clones a PHP variable.
     *
     * @param int $filter A bit field of Caster::EXCLUDE_* constants
     */
    
public function cloneVar(mixed $var, int $filter = 0): Data
    
{
        
$this->prevErrorHandler = set_error_handler(function ($type, $msg, $file, $line, $context = []) {
            if (
E_RECOVERABLE_ERROR === $type || E_USER_ERROR === $type) {
                
// Cloner never dies
                
throw new ErrorException($msg, 0, $type, $file, $line);
            }

            if (
$this->prevErrorHandler) {
                return (
$this->prevErrorHandler)($type, $msg, $file, $line, $context);
            }

            return 
false;
        });
        
$this->filter = $filter;

        if (
$gc = gc_enabled()) {
            
gc_disable();
        }
        try {
            return new 
Data($this->doClone($var));
        } finally {
            if (
$gc) {
                
gc_enable();
            }
            
restore_error_handler();
            
$this->prevErrorHandler = null;
        }
    }

    
/**
     * Effectively clones the PHP variable.
     */
    
abstract protected function doClone(mixed $var): array;

    
/**
     * Casts an object to an array representation.
     *
     * @param bool $isNested True if the object is nested in the dumped structure
     */
    
protected function castObject(Stub $stub, bool $isNested): array
    {
        
$obj = $stub->value;
        
$class = $stub->class;

        if (
str_contains($class, "@anonymous")) {
            
$stub->class = get_debug_type($obj);
        }
        if (isset(
$this->classInfo[$class])) {
            [
$i, $parents, $hasDebugInfo, $fileInfo] = $this->classInfo[$class];
        } else {
            
$i = 2;
            
$parents = [$class];
            
$hasDebugInfo = method_exists($class, '__debugInfo');

            foreach (
class_parents($class) as $p) {
                
$parents[] = $p;
                ++
$i;
            }
            foreach (
class_implements($class) as $p) {
                
$parents[] = $p;
                ++
$i;
            }
            
$parents[] = '*';

            
$r = new ReflectionClass($class);
            
$fileInfo = $r->isInternal() || $r->isSubclassOf(Stub::class) ? [] : [
                
'file' => $r->getFileName(),
                
'line' => $r->getStartLine(),
            ];

            
$this->classInfo[$class] = [$i, $parents, $hasDebugInfo, $fileInfo];
        }

        
$stub->attr += $fileInfo;
        
$a = Caster::castObject($obj, $class, $hasDebugInfo, $stub->class);

        try {
            while (
$i--) {
                if (!empty(
$this->casters[$p = $parents[$i]])) {
                    foreach (
$this->casters[$p] as $callback) {
                        
$a = $callback($obj, $a, $stub, $isNested, $this->filter);
                    }
                }
            }
        } catch (
Exception $e) {
            
$a = [(Stub::TYPE_OBJECT === $stub->type ? Caster::PREFIX_VIRTUAL : '').'⚠' => new ThrowingCasterException($e)] + $a;
        }

        return 
$a;
    }

    
/**
     * Casts a resource to an array representation.
     *
     * @param bool $isNested True if the object is nested in the dumped structure
     */
    
protected function castResource(Stub $stub, bool $isNested): array
    {
        
$a = [];
        
$res = $stub->value;
        
$type = $stub->class;

        try {
            if (!empty(
$this->casters[':'.$type])) {
                foreach (
$this->casters[':'.$type] as $callback) {
                    
$a = $callback($res, $a, $stub, $isNested, $this->filter);
                }
            }
        } catch (
Exception $e) {
            
$a = [(Stub::TYPE_OBJECT === $stub->type ? Caster::PREFIX_VIRTUAL : '').'⚠' => new ThrowingCasterException($e)] + $a;
        }

        return 
$a;
    }
}
Онлайн: 2
Реклама