db backup prior to drupal security update
[yaffs-website] / vendor / symfony / var-dumper / Cloner / AbstractCloner.php
1 <?php
2
3 /*
4  * This file is part of the Symfony package.
5  *
6  * (c) Fabien Potencier <fabien@symfony.com>
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11
12 namespace Symfony\Component\VarDumper\Cloner;
13
14 use Symfony\Component\VarDumper\Caster\Caster;
15 use Symfony\Component\VarDumper\Exception\ThrowingCasterException;
16
17 /**
18  * AbstractCloner implements a generic caster mechanism for objects and resources.
19  *
20  * @author Nicolas Grekas <p@tchwork.com>
21  */
22 abstract class AbstractCloner implements ClonerInterface
23 {
24     public static $defaultCasters = array(
25         'Symfony\Component\VarDumper\Caster\CutStub' => 'Symfony\Component\VarDumper\Caster\StubCaster::castStub',
26         'Symfony\Component\VarDumper\Caster\CutArrayStub' => 'Symfony\Component\VarDumper\Caster\StubCaster::castCutArray',
27         'Symfony\Component\VarDumper\Caster\ConstStub' => 'Symfony\Component\VarDumper\Caster\StubCaster::castStub',
28         'Symfony\Component\VarDumper\Caster\EnumStub' => 'Symfony\Component\VarDumper\Caster\StubCaster::castEnum',
29
30         'Closure' => 'Symfony\Component\VarDumper\Caster\ReflectionCaster::castClosure',
31         'Generator' => 'Symfony\Component\VarDumper\Caster\ReflectionCaster::castGenerator',
32         'ReflectionType' => 'Symfony\Component\VarDumper\Caster\ReflectionCaster::castType',
33         'ReflectionGenerator' => 'Symfony\Component\VarDumper\Caster\ReflectionCaster::castReflectionGenerator',
34         'ReflectionClass' => 'Symfony\Component\VarDumper\Caster\ReflectionCaster::castClass',
35         'ReflectionFunctionAbstract' => 'Symfony\Component\VarDumper\Caster\ReflectionCaster::castFunctionAbstract',
36         'ReflectionMethod' => 'Symfony\Component\VarDumper\Caster\ReflectionCaster::castMethod',
37         'ReflectionParameter' => 'Symfony\Component\VarDumper\Caster\ReflectionCaster::castParameter',
38         'ReflectionProperty' => 'Symfony\Component\VarDumper\Caster\ReflectionCaster::castProperty',
39         'ReflectionExtension' => 'Symfony\Component\VarDumper\Caster\ReflectionCaster::castExtension',
40         'ReflectionZendExtension' => 'Symfony\Component\VarDumper\Caster\ReflectionCaster::castZendExtension',
41
42         'Doctrine\Common\Persistence\ObjectManager' => 'Symfony\Component\VarDumper\Caster\StubCaster::cutInternals',
43         'Doctrine\Common\Proxy\Proxy' => 'Symfony\Component\VarDumper\Caster\DoctrineCaster::castCommonProxy',
44         'Doctrine\ORM\Proxy\Proxy' => 'Symfony\Component\VarDumper\Caster\DoctrineCaster::castOrmProxy',
45         'Doctrine\ORM\PersistentCollection' => 'Symfony\Component\VarDumper\Caster\DoctrineCaster::castPersistentCollection',
46
47         'DOMException' => 'Symfony\Component\VarDumper\Caster\DOMCaster::castException',
48         'DOMStringList' => 'Symfony\Component\VarDumper\Caster\DOMCaster::castLength',
49         'DOMNameList' => 'Symfony\Component\VarDumper\Caster\DOMCaster::castLength',
50         'DOMImplementation' => 'Symfony\Component\VarDumper\Caster\DOMCaster::castImplementation',
51         'DOMImplementationList' => 'Symfony\Component\VarDumper\Caster\DOMCaster::castLength',
52         'DOMNode' => 'Symfony\Component\VarDumper\Caster\DOMCaster::castNode',
53         'DOMNameSpaceNode' => 'Symfony\Component\VarDumper\Caster\DOMCaster::castNameSpaceNode',
54         'DOMDocument' => 'Symfony\Component\VarDumper\Caster\DOMCaster::castDocument',
55         'DOMNodeList' => 'Symfony\Component\VarDumper\Caster\DOMCaster::castLength',
56         'DOMNamedNodeMap' => 'Symfony\Component\VarDumper\Caster\DOMCaster::castLength',
57         'DOMCharacterData' => 'Symfony\Component\VarDumper\Caster\DOMCaster::castCharacterData',
58         'DOMAttr' => 'Symfony\Component\VarDumper\Caster\DOMCaster::castAttr',
59         'DOMElement' => 'Symfony\Component\VarDumper\Caster\DOMCaster::castElement',
60         'DOMText' => 'Symfony\Component\VarDumper\Caster\DOMCaster::castText',
61         'DOMTypeinfo' => 'Symfony\Component\VarDumper\Caster\DOMCaster::castTypeinfo',
62         'DOMDomError' => 'Symfony\Component\VarDumper\Caster\DOMCaster::castDomError',
63         'DOMLocator' => 'Symfony\Component\VarDumper\Caster\DOMCaster::castLocator',
64         'DOMDocumentType' => 'Symfony\Component\VarDumper\Caster\DOMCaster::castDocumentType',
65         'DOMNotation' => 'Symfony\Component\VarDumper\Caster\DOMCaster::castNotation',
66         'DOMEntity' => 'Symfony\Component\VarDumper\Caster\DOMCaster::castEntity',
67         'DOMProcessingInstruction' => 'Symfony\Component\VarDumper\Caster\DOMCaster::castProcessingInstruction',
68         'DOMXPath' => 'Symfony\Component\VarDumper\Caster\DOMCaster::castXPath',
69
70         'ErrorException' => 'Symfony\Component\VarDumper\Caster\ExceptionCaster::castErrorException',
71         'Exception' => 'Symfony\Component\VarDumper\Caster\ExceptionCaster::castException',
72         'Error' => 'Symfony\Component\VarDumper\Caster\ExceptionCaster::castError',
73         'Symfony\Component\DependencyInjection\ContainerInterface' => 'Symfony\Component\VarDumper\Caster\StubCaster::cutInternals',
74         'Symfony\Component\VarDumper\Exception\ThrowingCasterException' => 'Symfony\Component\VarDumper\Caster\ExceptionCaster::castThrowingCasterException',
75         'Symfony\Component\VarDumper\Caster\TraceStub' => 'Symfony\Component\VarDumper\Caster\ExceptionCaster::castTraceStub',
76         'Symfony\Component\VarDumper\Caster\FrameStub' => 'Symfony\Component\VarDumper\Caster\ExceptionCaster::castFrameStub',
77
78         'PHPUnit_Framework_MockObject_MockObject' => 'Symfony\Component\VarDumper\Caster\StubCaster::cutInternals',
79         'Prophecy\Prophecy\ProphecySubjectInterface' => 'Symfony\Component\VarDumper\Caster\StubCaster::cutInternals',
80         'Mockery\MockInterface' => 'Symfony\Component\VarDumper\Caster\StubCaster::cutInternals',
81
82         'PDO' => 'Symfony\Component\VarDumper\Caster\PdoCaster::castPdo',
83         'PDOStatement' => 'Symfony\Component\VarDumper\Caster\PdoCaster::castPdoStatement',
84
85         'AMQPConnection' => 'Symfony\Component\VarDumper\Caster\AmqpCaster::castConnection',
86         'AMQPChannel' => 'Symfony\Component\VarDumper\Caster\AmqpCaster::castChannel',
87         'AMQPQueue' => 'Symfony\Component\VarDumper\Caster\AmqpCaster::castQueue',
88         'AMQPExchange' => 'Symfony\Component\VarDumper\Caster\AmqpCaster::castExchange',
89         'AMQPEnvelope' => 'Symfony\Component\VarDumper\Caster\AmqpCaster::castEnvelope',
90
91         'ArrayObject' => 'Symfony\Component\VarDumper\Caster\SplCaster::castArrayObject',
92         'SplDoublyLinkedList' => 'Symfony\Component\VarDumper\Caster\SplCaster::castDoublyLinkedList',
93         'SplFileInfo' => 'Symfony\Component\VarDumper\Caster\SplCaster::castFileInfo',
94         'SplFileObject' => 'Symfony\Component\VarDumper\Caster\SplCaster::castFileObject',
95         'SplFixedArray' => 'Symfony\Component\VarDumper\Caster\SplCaster::castFixedArray',
96         'SplHeap' => 'Symfony\Component\VarDumper\Caster\SplCaster::castHeap',
97         'SplObjectStorage' => 'Symfony\Component\VarDumper\Caster\SplCaster::castObjectStorage',
98         'SplPriorityQueue' => 'Symfony\Component\VarDumper\Caster\SplCaster::castHeap',
99         'OuterIterator' => 'Symfony\Component\VarDumper\Caster\SplCaster::castOuterIterator',
100
101         'MongoCursorInterface' => 'Symfony\Component\VarDumper\Caster\MongoCaster::castCursor',
102
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
119     protected $maxItems = 2500;
120     protected $maxString = -1;
121     protected $useExt;
122
123     private $casters = array();
124     private $prevErrorHandler;
125     private $classInfo = array();
126     private $filter = 0;
127
128     /**
129      * @param callable[]|null $casters A map of casters
130      *
131      * @see addCasters
132      */
133     public function __construct(array $casters = null)
134     {
135         if (null === $casters) {
136             $casters = static::$defaultCasters;
137         }
138         $this->addCasters($casters);
139         $this->useExt = extension_loaded('symfony_debug');
140     }
141
142     /**
143      * Adds casters for resources and objects.
144      *
145      * Maps resources or objects types to a callback.
146      * Types are in the key, with a callable caster for value.
147      * Resource types are to be prefixed with a `:`,
148      * see e.g. static::$defaultCasters.
149      *
150      * @param callable[] $casters A map of casters
151      */
152     public function addCasters(array $casters)
153     {
154         foreach ($casters as $type => $callback) {
155             $this->casters[strtolower($type)][] = $callback;
156         }
157     }
158
159     /**
160      * Sets the maximum number of items to clone past the first level in nested structures.
161      *
162      * @param int $maxItems
163      */
164     public function setMaxItems($maxItems)
165     {
166         $this->maxItems = (int) $maxItems;
167     }
168
169     /**
170      * Sets the maximum cloned length for strings.
171      *
172      * @param int $maxString
173      */
174     public function setMaxString($maxString)
175     {
176         $this->maxString = (int) $maxString;
177     }
178
179     /**
180      * Clones a PHP variable.
181      *
182      * @param mixed $var    Any PHP variable
183      * @param int   $filter A bit field of Caster::EXCLUDE_* constants
184      *
185      * @return Data The cloned variable represented by a Data object
186      */
187     public function cloneVar($var, $filter = 0)
188     {
189         $this->filter = $filter;
190         $this->prevErrorHandler = set_error_handler(array($this, 'handleError'));
191         try {
192             $data = $this->doClone($var);
193         } catch (\Exception $e) {
194         }
195         restore_error_handler();
196         $this->prevErrorHandler = null;
197
198         if (isset($e)) {
199             throw $e;
200         }
201
202         return new Data($data);
203     }
204
205     /**
206      * Effectively clones the PHP variable.
207      *
208      * @param mixed $var Any PHP variable
209      *
210      * @return array The cloned variable represented in an array
211      */
212     abstract protected function doClone($var);
213
214     /**
215      * Casts an object to an array representation.
216      *
217      * @param Stub $stub     The Stub for the casted object
218      * @param bool $isNested True if the object is nested in the dumped structure
219      *
220      * @return array The object casted as array
221      */
222     protected function castObject(Stub $stub, $isNested)
223     {
224         $obj = $stub->value;
225         $class = $stub->class;
226
227         if (isset($class[15]) && "\0" === $class[15] && 0 === strpos($class, "class@anonymous\x00")) {
228             $stub->class = get_parent_class($class).'@anonymous';
229         }
230         if (isset($this->classInfo[$class])) {
231             $classInfo = $this->classInfo[$class];
232         } else {
233             $classInfo = array(
234                 new \ReflectionClass($class),
235                 array_reverse(array($class => $class) + class_parents($class) + class_implements($class) + array('*' => '*')),
236             );
237
238             $this->classInfo[$class] = $classInfo;
239         }
240
241         $a = $this->callCaster('Symfony\Component\VarDumper\Caster\Caster::castObject', $obj, $classInfo[0], null, $isNested);
242
243         foreach ($classInfo[1] as $p) {
244             if (!empty($this->casters[$p = strtolower($p)])) {
245                 foreach ($this->casters[$p] as $p) {
246                     $a = $this->callCaster($p, $obj, $a, $stub, $isNested);
247                 }
248             }
249         }
250
251         return $a;
252     }
253
254     /**
255      * Casts a resource to an array representation.
256      *
257      * @param Stub $stub     The Stub for the casted resource
258      * @param bool $isNested True if the object is nested in the dumped structure
259      *
260      * @return array The resource casted as array
261      */
262     protected function castResource(Stub $stub, $isNested)
263     {
264         $a = array();
265         $res = $stub->value;
266         $type = $stub->class;
267
268         if (!empty($this->casters[':'.$type])) {
269             foreach ($this->casters[':'.$type] as $c) {
270                 $a = $this->callCaster($c, $res, $a, $stub, $isNested);
271             }
272         }
273
274         return $a;
275     }
276
277     /**
278      * Calls a custom caster.
279      *
280      * @param callable        $callback The caster
281      * @param object|resource $obj      The object/resource being casted
282      * @param array           $a        The result of the previous cast for chained casters
283      * @param Stub            $stub     The Stub for the casted object/resource
284      * @param bool            $isNested True if $obj is nested in the dumped structure
285      *
286      * @return array The casted object/resource
287      */
288     private function callCaster($callback, $obj, $a, $stub, $isNested)
289     {
290         try {
291             $cast = call_user_func($callback, $obj, $a, $stub, $isNested, $this->filter);
292
293             if (is_array($cast)) {
294                 $a = $cast;
295             }
296         } catch (\Exception $e) {
297             $a[(Stub::TYPE_OBJECT === $stub->type ? Caster::PREFIX_VIRTUAL : '').'⚠'] = new ThrowingCasterException($e);
298         }
299
300         return $a;
301     }
302
303     /**
304      * Special handling for errors: cloning must be fail-safe.
305      *
306      * @internal
307      */
308     public function handleError($type, $msg, $file, $line, $context)
309     {
310         if (E_RECOVERABLE_ERROR === $type || E_USER_ERROR === $type) {
311             // Cloner never dies
312             throw new \ErrorException($msg, 0, $type, $file, $line);
313         }
314
315         if ($this->prevErrorHandler) {
316             return call_user_func($this->prevErrorHandler, $type, $msg, $file, $line, $context);
317         }
318
319         return false;
320     }
321 }