vendor/symfony/var-dumper/Cloner/AbstractCloner.php line 270
<?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\VarDumper\Cloner;use Symfony\Component\VarDumper\Caster\Caster;use Symfony\Component\VarDumper\Exception\ThrowingCasterException;/*** AbstractCloner implements a generic caster mechanism for objects and resources.** @author Nicolas Grekas <p@tchwork.com>*/abstract class AbstractCloner implements ClonerInterface{public static $defaultCasters = ['__PHP_Incomplete_Class' => ['Symfony\Component\VarDumper\Caster\Caster', 'castPhpIncompleteClass'],'Symfony\Component\VarDumper\Caster\CutStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castStub'],'Symfony\Component\VarDumper\Caster\CutArrayStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castCutArray'],'Symfony\Component\VarDumper\Caster\ConstStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castStub'],'Symfony\Component\VarDumper\Caster\EnumStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castEnum'],'Fiber' => ['Symfony\Component\VarDumper\Caster\FiberCaster', 'castFiber'],'Closure' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castClosure'],'Generator' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castGenerator'],'ReflectionType' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castType'],'ReflectionAttribute' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castAttribute'],'ReflectionGenerator' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castReflectionGenerator'],'ReflectionClass' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castClass'],'ReflectionClassConstant' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castClassConstant'],'ReflectionFunctionAbstract' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castFunctionAbstract'],'ReflectionMethod' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castMethod'],'ReflectionParameter' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castParameter'],'ReflectionProperty' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castProperty'],'ReflectionReference' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castReference'],'ReflectionExtension' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castExtension'],'ReflectionZendExtension' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castZendExtension'],'Doctrine\Common\Persistence\ObjectManager' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'],'Doctrine\Common\Proxy\Proxy' => ['Symfony\Component\VarDumper\Caster\DoctrineCaster', 'castCommonProxy'],'Doctrine\ORM\Proxy\Proxy' => ['Symfony\Component\VarDumper\Caster\DoctrineCaster', 'castOrmProxy'],'Doctrine\ORM\PersistentCollection' => ['Symfony\Component\VarDumper\Caster\DoctrineCaster', 'castPersistentCollection'],'Doctrine\Persistence\ObjectManager' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'],'DOMException' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castException'],'DOMStringList' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'],'DOMNameList' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'],'DOMImplementation' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castImplementation'],'DOMImplementationList' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'],'DOMNode' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castNode'],'DOMNameSpaceNode' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castNameSpaceNode'],'DOMDocument' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castDocument'],'DOMNodeList' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'],'DOMNamedNodeMap' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'],'DOMCharacterData' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castCharacterData'],'DOMAttr' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castAttr'],'DOMElement' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castElement'],'DOMText' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castText'],'DOMDocumentType' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castDocumentType'],'DOMNotation' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castNotation'],'DOMEntity' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castEntity'],'DOMProcessingInstruction' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castProcessingInstruction'],'DOMXPath' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castXPath'],'XMLReader' => ['Symfony\Component\VarDumper\Caster\XmlReaderCaster', 'castXmlReader'],'ErrorException' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castErrorException'],'Exception' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castException'],'Error' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castError'],'Symfony\Bridge\Monolog\Logger' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'],'Symfony\Component\DependencyInjection\ContainerInterface' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'],'Symfony\Component\EventDispatcher\EventDispatcherInterface' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'],'Symfony\Component\HttpClient\AmpHttpClient' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClient'],'Symfony\Component\HttpClient\CurlHttpClient' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClient'],'Symfony\Component\HttpClient\NativeHttpClient' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClient'],'Symfony\Component\HttpClient\Response\AmpResponse' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClientResponse'],'Symfony\Component\HttpClient\Response\CurlResponse' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClientResponse'],'Symfony\Component\HttpClient\Response\NativeResponse' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClientResponse'],'Symfony\Component\HttpFoundation\Request' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castRequest'],'Symfony\Component\Uid\Ulid' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castUlid'],'Symfony\Component\Uid\Uuid' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castUuid'],'Symfony\Component\VarExporter\Internal\LazyObjectState' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castLazyObjectState'],'Symfony\Component\VarDumper\Exception\ThrowingCasterException' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castThrowingCasterException'],'Symfony\Component\VarDumper\Caster\TraceStub' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castTraceStub'],'Symfony\Component\VarDumper\Caster\FrameStub' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castFrameStub'],'Symfony\Component\VarDumper\Cloner\AbstractCloner' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'],'Symfony\Component\ErrorHandler\Exception\SilencedErrorContext' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castSilencedErrorContext'],'Imagine\Image\ImageInterface' => ['Symfony\Component\VarDumper\Caster\ImagineCaster', 'castImage'],'Ramsey\Uuid\UuidInterface' => ['Symfony\Component\VarDumper\Caster\UuidCaster', 'castRamseyUuid'],'ProxyManager\Proxy\ProxyInterface' => ['Symfony\Component\VarDumper\Caster\ProxyManagerCaster', 'castProxy'],'PHPUnit_Framework_MockObject_MockObject' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'],'PHPUnit\Framework\MockObject\MockObject' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'],'PHPUnit\Framework\MockObject\Stub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'],'Prophecy\Prophecy\ProphecySubjectInterface' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'],'Mockery\MockInterface' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'],'PDO' => ['Symfony\Component\VarDumper\Caster\PdoCaster', 'castPdo'],'PDOStatement' => ['Symfony\Component\VarDumper\Caster\PdoCaster', 'castPdoStatement'],'AMQPConnection' => ['Symfony\Component\VarDumper\Caster\AmqpCaster', 'castConnection'],'AMQPChannel' => ['Symfony\Component\VarDumper\Caster\AmqpCaster', 'castChannel'],'AMQPQueue' => ['Symfony\Component\VarDumper\Caster\AmqpCaster', 'castQueue'],'AMQPExchange' => ['Symfony\Component\VarDumper\Caster\AmqpCaster', 'castExchange'],'AMQPEnvelope' => ['Symfony\Component\VarDumper\Caster\AmqpCaster', 'castEnvelope'],'ArrayObject' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castArrayObject'],'ArrayIterator' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castArrayIterator'],'SplDoublyLinkedList' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castDoublyLinkedList'],'SplFileInfo' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castFileInfo'],'SplFileObject' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castFileObject'],'SplHeap' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castHeap'],'SplObjectStorage' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castObjectStorage'],'SplPriorityQueue' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castHeap'],'OuterIterator' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castOuterIterator'],'WeakReference' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castWeakReference'],'Redis' => ['Symfony\Component\VarDumper\Caster\RedisCaster', 'castRedis'],'RedisArray' => ['Symfony\Component\VarDumper\Caster\RedisCaster', 'castRedisArray'],'RedisCluster' => ['Symfony\Component\VarDumper\Caster\RedisCaster', 'castRedisCluster'],'DateTimeInterface' => ['Symfony\Component\VarDumper\Caster\DateCaster', 'castDateTime'],'DateInterval' => ['Symfony\Component\VarDumper\Caster\DateCaster', 'castInterval'],'DateTimeZone' => ['Symfony\Component\VarDumper\Caster\DateCaster', 'castTimeZone'],'DatePeriod' => ['Symfony\Component\VarDumper\Caster\DateCaster', 'castPeriod'],'GMP' => ['Symfony\Component\VarDumper\Caster\GmpCaster', 'castGmp'],'MessageFormatter' => ['Symfony\Component\VarDumper\Caster\IntlCaster', 'castMessageFormatter'],'NumberFormatter' => ['Symfony\Component\VarDumper\Caster\IntlCaster', 'castNumberFormatter'],'IntlTimeZone' => ['Symfony\Component\VarDumper\Caster\IntlCaster', 'castIntlTimeZone'],'IntlCalendar' => ['Symfony\Component\VarDumper\Caster\IntlCaster', 'castIntlCalendar'],'IntlDateFormatter' => ['Symfony\Component\VarDumper\Caster\IntlCaster', 'castIntlDateFormatter'],'Memcached' => ['Symfony\Component\VarDumper\Caster\MemcachedCaster', 'castMemcached'],'Ds\Collection' => ['Symfony\Component\VarDumper\Caster\DsCaster', 'castCollection'],'Ds\Map' => ['Symfony\Component\VarDumper\Caster\DsCaster', 'castMap'],'Ds\Pair' => ['Symfony\Component\VarDumper\Caster\DsCaster', 'castPair'],'Symfony\Component\VarDumper\Caster\DsPairStub' => ['Symfony\Component\VarDumper\Caster\DsCaster', 'castPairStub'],'mysqli_driver' => ['Symfony\Component\VarDumper\Caster\MysqliCaster', 'castMysqliDriver'],'CurlHandle' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castCurl'],':dba' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castDba'],':dba persistent' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castDba'],'GdImage' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castGd'],':gd' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castGd'],':pgsql large object' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castLargeObject'],':pgsql link' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castLink'],':pgsql link persistent' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castLink'],':pgsql result' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castResult'],':process' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castProcess'],':stream' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castStream'],'OpenSSLCertificate' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castOpensslX509'],':OpenSSL X.509' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castOpensslX509'],':persistent stream' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castStream'],':stream-context' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castStreamContext'],'XmlParser' => ['Symfony\Component\VarDumper\Caster\XmlResourceCaster', 'castXml'],':xml' => ['Symfony\Component\VarDumper\Caster\XmlResourceCaster', 'castXml'],'RdKafka' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castRdKafka'],'RdKafka\Conf' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castConf'],'RdKafka\KafkaConsumer' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castKafkaConsumer'],'RdKafka\Metadata\Broker' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castBrokerMetadata'],'RdKafka\Metadata\Collection' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castCollectionMetadata'],'RdKafka\Metadata\Partition' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castPartitionMetadata'],'RdKafka\Metadata\Topic' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castTopicMetadata'],'RdKafka\Message' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castMessage'],'RdKafka\Topic' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castTopic'],'RdKafka\TopicPartition' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castTopicPartition'],'RdKafka\TopicConf' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castTopicConf'],'FFI\CData' => ['Symfony\Component\VarDumper\Caster\FFICaster', 'castCTypeOrCData'],'FFI\CType' => ['Symfony\Component\VarDumper\Caster\FFICaster', 'castCTypeOrCData'],];protected $maxItems = 2500;protected $maxString = -1;protected $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 objects types to a callback.* Types are in the key, with a callable caster for value.* Resource types are to be prefixed with a `:`,* see e.g. static::$defaultCasters.** @param callable[] $casters A map of casters*/public function addCasters(array $casters){foreach ($casters as $type => $callback) {$this->casters[$type][] = $callback;}}/*** Sets the maximum number of items to clone past the minimum depth in nested structures.*/public function setMaxItems(int $maxItems){$this->maxItems = $maxItems;}/*** Sets the maximum cloned length for strings.*/public function setMaxString(int $maxString){$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){$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 diesthrow 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\0")) {$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;}}