vendor/symfony/symfony/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php line 304

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <fabien@symfony.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Symfony\Component\VarDumper\Cloner;
  11. use Symfony\Component\VarDumper\Caster\Caster;
  12. use Symfony\Component\VarDumper\Exception\ThrowingCasterException;
  13. /**
  14.  * AbstractCloner implements a generic caster mechanism for objects and resources.
  15.  *
  16.  * @author Nicolas Grekas <p@tchwork.com>
  17.  */
  18. abstract class AbstractCloner implements ClonerInterface
  19. {
  20.     public static $defaultCasters = [
  21.         '__PHP_Incomplete_Class' => ['Symfony\Component\VarDumper\Caster\Caster''castPhpIncompleteClass'],
  22.         'Symfony\Component\VarDumper\Caster\CutStub' => ['Symfony\Component\VarDumper\Caster\StubCaster''castStub'],
  23.         'Symfony\Component\VarDumper\Caster\CutArrayStub' => ['Symfony\Component\VarDumper\Caster\StubCaster''castCutArray'],
  24.         'Symfony\Component\VarDumper\Caster\ConstStub' => ['Symfony\Component\VarDumper\Caster\StubCaster''castStub'],
  25.         'Symfony\Component\VarDumper\Caster\EnumStub' => ['Symfony\Component\VarDumper\Caster\StubCaster''castEnum'],
  26.         'Closure' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster''castClosure'],
  27.         'Generator' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster''castGenerator'],
  28.         'ReflectionType' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster''castType'],
  29.         'ReflectionGenerator' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster''castReflectionGenerator'],
  30.         'ReflectionClass' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster''castClass'],
  31.         'ReflectionFunctionAbstract' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster''castFunctionAbstract'],
  32.         'ReflectionMethod' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster''castMethod'],
  33.         'ReflectionParameter' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster''castParameter'],
  34.         'ReflectionProperty' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster''castProperty'],
  35.         'ReflectionExtension' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster''castExtension'],
  36.         'ReflectionZendExtension' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster''castZendExtension'],
  37.         'Doctrine\Common\Persistence\ObjectManager' => ['Symfony\Component\VarDumper\Caster\StubCaster''cutInternals'],
  38.         'Doctrine\Common\Proxy\Proxy' => ['Symfony\Component\VarDumper\Caster\DoctrineCaster''castCommonProxy'],
  39.         'Doctrine\ORM\Proxy\Proxy' => ['Symfony\Component\VarDumper\Caster\DoctrineCaster''castOrmProxy'],
  40.         'Doctrine\ORM\PersistentCollection' => ['Symfony\Component\VarDumper\Caster\DoctrineCaster''castPersistentCollection'],
  41.         'Doctrine\Persistence\ObjectManager' => ['Symfony\Component\VarDumper\Caster\StubCaster''cutInternals'],
  42.         'DOMException' => ['Symfony\Component\VarDumper\Caster\DOMCaster''castException'],
  43.         'DOMStringList' => ['Symfony\Component\VarDumper\Caster\DOMCaster''castLength'],
  44.         'DOMNameList' => ['Symfony\Component\VarDumper\Caster\DOMCaster''castLength'],
  45.         'DOMImplementation' => ['Symfony\Component\VarDumper\Caster\DOMCaster''castImplementation'],
  46.         'DOMImplementationList' => ['Symfony\Component\VarDumper\Caster\DOMCaster''castLength'],
  47.         'DOMNode' => ['Symfony\Component\VarDumper\Caster\DOMCaster''castNode'],
  48.         'DOMNameSpaceNode' => ['Symfony\Component\VarDumper\Caster\DOMCaster''castNameSpaceNode'],
  49.         'DOMDocument' => ['Symfony\Component\VarDumper\Caster\DOMCaster''castDocument'],
  50.         'DOMNodeList' => ['Symfony\Component\VarDumper\Caster\DOMCaster''castLength'],
  51.         'DOMNamedNodeMap' => ['Symfony\Component\VarDumper\Caster\DOMCaster''castLength'],
  52.         'DOMCharacterData' => ['Symfony\Component\VarDumper\Caster\DOMCaster''castCharacterData'],
  53.         'DOMAttr' => ['Symfony\Component\VarDumper\Caster\DOMCaster''castAttr'],
  54.         'DOMElement' => ['Symfony\Component\VarDumper\Caster\DOMCaster''castElement'],
  55.         'DOMText' => ['Symfony\Component\VarDumper\Caster\DOMCaster''castText'],
  56.         'DOMTypeinfo' => ['Symfony\Component\VarDumper\Caster\DOMCaster''castTypeinfo'],
  57.         'DOMDomError' => ['Symfony\Component\VarDumper\Caster\DOMCaster''castDomError'],
  58.         'DOMLocator' => ['Symfony\Component\VarDumper\Caster\DOMCaster''castLocator'],
  59.         'DOMDocumentType' => ['Symfony\Component\VarDumper\Caster\DOMCaster''castDocumentType'],
  60.         'DOMNotation' => ['Symfony\Component\VarDumper\Caster\DOMCaster''castNotation'],
  61.         'DOMEntity' => ['Symfony\Component\VarDumper\Caster\DOMCaster''castEntity'],
  62.         'DOMProcessingInstruction' => ['Symfony\Component\VarDumper\Caster\DOMCaster''castProcessingInstruction'],
  63.         'DOMXPath' => ['Symfony\Component\VarDumper\Caster\DOMCaster''castXPath'],
  64.         'XmlReader' => ['Symfony\Component\VarDumper\Caster\XmlReaderCaster''castXmlReader'],
  65.         'ErrorException' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster''castErrorException'],
  66.         'Exception' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster''castException'],
  67.         'Error' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster''castError'],
  68.         'Symfony\Component\DependencyInjection\ContainerInterface' => ['Symfony\Component\VarDumper\Caster\StubCaster''cutInternals'],
  69.         'Symfony\Component\HttpFoundation\Request' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster''castRequest'],
  70.         'Symfony\Component\VarDumper\Exception\ThrowingCasterException' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster''castThrowingCasterException'],
  71.         'Symfony\Component\VarDumper\Caster\TraceStub' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster''castTraceStub'],
  72.         'Symfony\Component\VarDumper\Caster\FrameStub' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster''castFrameStub'],
  73.         'Symfony\Component\Debug\Exception\SilencedErrorContext' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster''castSilencedErrorContext'],
  74.         'PHPUnit_Framework_MockObject_MockObject' => ['Symfony\Component\VarDumper\Caster\StubCaster''cutInternals'],
  75.         'PHPUnit\Framework\MockObject\MockObject' => ['Symfony\Component\VarDumper\Caster\StubCaster''cutInternals'],
  76.         'PHPUnit\Framework\MockObject\Stub' => ['Symfony\Component\VarDumper\Caster\StubCaster''cutInternals'],
  77.         'Prophecy\Prophecy\ProphecySubjectInterface' => ['Symfony\Component\VarDumper\Caster\StubCaster''cutInternals'],
  78.         'Mockery\MockInterface' => ['Symfony\Component\VarDumper\Caster\StubCaster''cutInternals'],
  79.         'PDO' => ['Symfony\Component\VarDumper\Caster\PdoCaster''castPdo'],
  80.         'PDOStatement' => ['Symfony\Component\VarDumper\Caster\PdoCaster''castPdoStatement'],
  81.         'AMQPConnection' => ['Symfony\Component\VarDumper\Caster\AmqpCaster''castConnection'],
  82.         'AMQPChannel' => ['Symfony\Component\VarDumper\Caster\AmqpCaster''castChannel'],
  83.         'AMQPQueue' => ['Symfony\Component\VarDumper\Caster\AmqpCaster''castQueue'],
  84.         'AMQPExchange' => ['Symfony\Component\VarDumper\Caster\AmqpCaster''castExchange'],
  85.         'AMQPEnvelope' => ['Symfony\Component\VarDumper\Caster\AmqpCaster''castEnvelope'],
  86.         'ArrayObject' => ['Symfony\Component\VarDumper\Caster\SplCaster''castArrayObject'],
  87.         'ArrayIterator' => ['Symfony\Component\VarDumper\Caster\SplCaster''castArrayIterator'],
  88.         'SplDoublyLinkedList' => ['Symfony\Component\VarDumper\Caster\SplCaster''castDoublyLinkedList'],
  89.         'SplFileInfo' => ['Symfony\Component\VarDumper\Caster\SplCaster''castFileInfo'],
  90.         'SplFileObject' => ['Symfony\Component\VarDumper\Caster\SplCaster''castFileObject'],
  91.         'SplHeap' => ['Symfony\Component\VarDumper\Caster\SplCaster''castHeap'],
  92.         'SplObjectStorage' => ['Symfony\Component\VarDumper\Caster\SplCaster''castObjectStorage'],
  93.         'SplPriorityQueue' => ['Symfony\Component\VarDumper\Caster\SplCaster''castHeap'],
  94.         'OuterIterator' => ['Symfony\Component\VarDumper\Caster\SplCaster''castOuterIterator'],
  95.         'MongoCursorInterface' => ['Symfony\Component\VarDumper\Caster\MongoCaster''castCursor'],
  96.         'Redis' => ['Symfony\Component\VarDumper\Caster\RedisCaster''castRedis'],
  97.         'RedisArray' => ['Symfony\Component\VarDumper\Caster\RedisCaster''castRedisArray'],
  98.         'DateTimeInterface' => ['Symfony\Component\VarDumper\Caster\DateCaster''castDateTime'],
  99.         'DateInterval' => ['Symfony\Component\VarDumper\Caster\DateCaster''castInterval'],
  100.         'DateTimeZone' => ['Symfony\Component\VarDumper\Caster\DateCaster''castTimeZone'],
  101.         'DatePeriod' => ['Symfony\Component\VarDumper\Caster\DateCaster''castPeriod'],
  102.         'CurlHandle' => ['Symfony\Component\VarDumper\Caster\ResourceCaster''castCurl'],
  103.         ':curl' => ['Symfony\Component\VarDumper\Caster\ResourceCaster''castCurl'],
  104.         ':dba' => ['Symfony\Component\VarDumper\Caster\ResourceCaster''castDba'],
  105.         ':dba persistent' => ['Symfony\Component\VarDumper\Caster\ResourceCaster''castDba'],
  106.         ':gd' => ['Symfony\Component\VarDumper\Caster\ResourceCaster''castGd'],
  107.         ':mysql link' => ['Symfony\Component\VarDumper\Caster\ResourceCaster''castMysqlLink'],
  108.         ':pgsql large object' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster''castLargeObject'],
  109.         ':pgsql link' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster''castLink'],
  110.         ':pgsql link persistent' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster''castLink'],
  111.         ':pgsql result' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster''castResult'],
  112.         ':process' => ['Symfony\Component\VarDumper\Caster\ResourceCaster''castProcess'],
  113.         ':stream' => ['Symfony\Component\VarDumper\Caster\ResourceCaster''castStream'],
  114.         ':persistent stream' => ['Symfony\Component\VarDumper\Caster\ResourceCaster''castStream'],
  115.         ':stream-context' => ['Symfony\Component\VarDumper\Caster\ResourceCaster''castStreamContext'],
  116.         ':xml' => ['Symfony\Component\VarDumper\Caster\XmlResourceCaster''castXml'],
  117.     ];
  118.     protected $maxItems 2500;
  119.     protected $maxString = -1;
  120.     protected $minDepth 1;
  121.     protected $useExt;
  122.     private $casters = [];
  123.     private $prevErrorHandler;
  124.     private $classInfo = [];
  125.     private $filter 0;
  126.     /**
  127.      * @param callable[]|null $casters A map of casters
  128.      *
  129.      * @see addCasters
  130.      */
  131.     public function __construct(array $casters null)
  132.     {
  133.         if (null === $casters) {
  134.             $casters = static::$defaultCasters;
  135.         }
  136.         $this->addCasters($casters);
  137.         $this->useExt = \extension_loaded('symfony_debug');
  138.     }
  139.     /**
  140.      * Adds casters for resources and objects.
  141.      *
  142.      * Maps resources or objects types to a callback.
  143.      * Types are in the key, with a callable caster for value.
  144.      * Resource types are to be prefixed with a `:`,
  145.      * see e.g. static::$defaultCasters.
  146.      *
  147.      * @param callable[] $casters A map of casters
  148.      */
  149.     public function addCasters(array $casters)
  150.     {
  151.         foreach ($casters as $type => $callback) {
  152.             $this->casters[strtolower($type)][] = \is_string($callback) && false !== strpos($callback'::') ? explode('::'$callback2) : $callback;
  153.         }
  154.     }
  155.     /**
  156.      * Sets the maximum number of items to clone past the minimum depth in nested structures.
  157.      *
  158.      * @param int $maxItems
  159.      */
  160.     public function setMaxItems($maxItems)
  161.     {
  162.         $this->maxItems = (int) $maxItems;
  163.     }
  164.     /**
  165.      * Sets the maximum cloned length for strings.
  166.      *
  167.      * @param int $maxString
  168.      */
  169.     public function setMaxString($maxString)
  170.     {
  171.         $this->maxString = (int) $maxString;
  172.     }
  173.     /**
  174.      * Sets the minimum tree depth where we are guaranteed to clone all the items.  After this
  175.      * depth is reached, only setMaxItems items will be cloned.
  176.      *
  177.      * @param int $minDepth
  178.      */
  179.     public function setMinDepth($minDepth)
  180.     {
  181.         $this->minDepth = (int) $minDepth;
  182.     }
  183.     /**
  184.      * Clones a PHP variable.
  185.      *
  186.      * @param mixed $var    Any PHP variable
  187.      * @param int   $filter A bit field of Caster::EXCLUDE_* constants
  188.      *
  189.      * @return Data The cloned variable represented by a Data object
  190.      */
  191.     public function cloneVar($var$filter 0)
  192.     {
  193.         $this->prevErrorHandler set_error_handler(function ($type$msg$file$line$context = []) {
  194.             if (\E_RECOVERABLE_ERROR === $type || \E_USER_ERROR === $type) {
  195.                 // Cloner never dies
  196.                 throw new \ErrorException($msg0$type$file$line);
  197.             }
  198.             if ($this->prevErrorHandler) {
  199.                 return \call_user_func($this->prevErrorHandler$type$msg$file$line$context);
  200.             }
  201.             return false;
  202.         });
  203.         $this->filter $filter;
  204.         if ($gc gc_enabled()) {
  205.             gc_disable();
  206.         }
  207.         try {
  208.             return new Data($this->doClone($var));
  209.         } finally {
  210.             if ($gc) {
  211.                 gc_enable();
  212.             }
  213.             restore_error_handler();
  214.             $this->prevErrorHandler null;
  215.         }
  216.     }
  217.     /**
  218.      * Effectively clones the PHP variable.
  219.      *
  220.      * @param mixed $var Any PHP variable
  221.      *
  222.      * @return array The cloned variable represented in an array
  223.      */
  224.     abstract protected function doClone($var);
  225.     /**
  226.      * Casts an object to an array representation.
  227.      *
  228.      * @param Stub $stub     The Stub for the casted object
  229.      * @param bool $isNested True if the object is nested in the dumped structure
  230.      *
  231.      * @return array The object casted as array
  232.      */
  233.     protected function castObject(Stub $stub$isNested)
  234.     {
  235.         $obj $stub->value;
  236.         $class $stub->class;
  237.         if ((\PHP_VERSION_ID >= 80000 || (isset($class[15]) && "\0" === $class[15])) && false !== strpos($class"@anonymous\0")) {
  238.             $stub->class = \PHP_VERSION_ID 80000 ? (get_parent_class($class) ?: key(class_implements($class)) ?: 'class').'@anonymous' get_debug_type($obj);
  239.         }
  240.         if (isset($this->classInfo[$class])) {
  241.             list($i$parents$hasDebugInfo) = $this->classInfo[$class];
  242.         } else {
  243.             $i 2;
  244.             $parents = [strtolower($class)];
  245.             $hasDebugInfo method_exists($class'__debugInfo');
  246.             foreach (class_parents($class) as $p) {
  247.                 $parents[] = strtolower($p);
  248.                 ++$i;
  249.             }
  250.             foreach (class_implements($class) as $p) {
  251.                 $parents[] = strtolower($p);
  252.                 ++$i;
  253.             }
  254.             $parents[] = '*';
  255.             $this->classInfo[$class] = [$i$parents$hasDebugInfo];
  256.         }
  257.         $a Caster::castObject($obj$class$hasDebugInfo$stub->class);
  258.         try {
  259.             while ($i--) {
  260.                 if (!empty($this->casters[$p $parents[$i]])) {
  261.                     foreach ($this->casters[$p] as $callback) {
  262.                         $a $callback($obj$a$stub$isNested$this->filter);
  263.                     }
  264.                 }
  265.             }
  266.         } catch (\Exception $e) {
  267.             $a = [(Stub::TYPE_OBJECT === $stub->type Caster::PREFIX_VIRTUAL '').'⚠' => new ThrowingCasterException($e)] + $a;
  268.         }
  269.         return $a;
  270.     }
  271.     /**
  272.      * Casts a resource to an array representation.
  273.      *
  274.      * @param Stub $stub     The Stub for the casted resource
  275.      * @param bool $isNested True if the object is nested in the dumped structure
  276.      *
  277.      * @return array The resource casted as array
  278.      */
  279.     protected function castResource(Stub $stub$isNested)
  280.     {
  281.         $a = [];
  282.         $res $stub->value;
  283.         $type $stub->class;
  284.         try {
  285.             if (!empty($this->casters[':'.$type])) {
  286.                 foreach ($this->casters[':'.$type] as $callback) {
  287.                     $a $callback($res$a$stub$isNested$this->filter);
  288.                 }
  289.             }
  290.         } catch (\Exception $e) {
  291.             $a = [(Stub::TYPE_OBJECT === $stub->type Caster::PREFIX_VIRTUAL '').'⚠' => new ThrowingCasterException($e)] + $a;
  292.         }
  293.         return $a;
  294.     }
  295. }