comparison vendor/symfony/var-dumper/Cloner/Data.php @ 0:c75dbcec494b

Initial commit from drush-created site
author Chris Cannam
date Thu, 05 Jul 2018 14:24:15 +0000
parents
children a9cd425dd02b
comparison
equal deleted inserted replaced
-1:000000000000 0:c75dbcec494b
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
16 /**
17 * @author Nicolas Grekas <p@tchwork.com>
18 */
19 class Data implements \ArrayAccess, \Countable, \IteratorAggregate
20 {
21 private $data;
22 private $position = 0;
23 private $key = 0;
24 private $maxDepth = 20;
25 private $maxItemsPerDepth = -1;
26 private $useRefHandles = -1;
27
28 /**
29 * @param array $data An array as returned by ClonerInterface::cloneVar()
30 */
31 public function __construct(array $data)
32 {
33 $this->data = $data;
34 }
35
36 /**
37 * @return string The type of the value
38 */
39 public function getType()
40 {
41 $item = $this->data[$this->position][$this->key];
42
43 if ($item instanceof Stub && Stub::TYPE_REF === $item->type && !$item->position) {
44 $item = $item->value;
45 }
46 if (!$item instanceof Stub) {
47 return gettype($item);
48 }
49 if (Stub::TYPE_STRING === $item->type) {
50 return 'string';
51 }
52 if (Stub::TYPE_ARRAY === $item->type) {
53 return 'array';
54 }
55 if (Stub::TYPE_OBJECT === $item->type) {
56 return $item->class;
57 }
58 if (Stub::TYPE_RESOURCE === $item->type) {
59 return $item->class.' resource';
60 }
61 }
62
63 /**
64 * @param bool $recursive Whether values should be resolved recursively or not
65 *
66 * @return string|int|float|bool|array|null|Data[] A native representation of the original value
67 */
68 public function getValue($recursive = false)
69 {
70 $item = $this->data[$this->position][$this->key];
71
72 if ($item instanceof Stub && Stub::TYPE_REF === $item->type && !$item->position) {
73 $item = $item->value;
74 }
75 if (!($item = $this->getStub($item)) instanceof Stub) {
76 return $item;
77 }
78 if (Stub::TYPE_STRING === $item->type) {
79 return $item->value;
80 }
81
82 $children = $item->position ? $this->data[$item->position] : array();
83
84 foreach ($children as $k => $v) {
85 if ($recursive && !($v = $this->getStub($v)) instanceof Stub) {
86 continue;
87 }
88 $children[$k] = clone $this;
89 $children[$k]->key = $k;
90 $children[$k]->position = $item->position;
91
92 if ($recursive) {
93 if (Stub::TYPE_REF === $v->type && ($v = $this->getStub($v->value)) instanceof Stub) {
94 $recursive = (array) $recursive;
95 if (isset($recursive[$v->position])) {
96 continue;
97 }
98 $recursive[$v->position] = true;
99 }
100 $children[$k] = $children[$k]->getValue($recursive);
101 }
102 }
103
104 return $children;
105 }
106
107 public function count()
108 {
109 return count($this->getValue());
110 }
111
112 public function getIterator()
113 {
114 if (!is_array($value = $this->getValue())) {
115 throw new \LogicException(sprintf('%s object holds non-iterable type "%s".', self::class, gettype($value)));
116 }
117
118 foreach ($value as $k => $v) {
119 yield $k => $v;
120 }
121 }
122
123 public function __get($key)
124 {
125 if (null !== $data = $this->seek($key)) {
126 $item = $this->getStub($data->data[$data->position][$data->key]);
127
128 return $item instanceof Stub || array() === $item ? $data : $item;
129 }
130 }
131
132 public function __isset($key)
133 {
134 return null !== $this->seek($key);
135 }
136
137 public function offsetExists($key)
138 {
139 return $this->__isset($key);
140 }
141
142 public function offsetGet($key)
143 {
144 return $this->__get($key);
145 }
146
147 public function offsetSet($key, $value)
148 {
149 throw new \BadMethodCallException(self::class.' objects are immutable.');
150 }
151
152 public function offsetUnset($key)
153 {
154 throw new \BadMethodCallException(self::class.' objects are immutable.');
155 }
156
157 public function __toString()
158 {
159 $value = $this->getValue();
160
161 if (!is_array($value)) {
162 return (string) $value;
163 }
164
165 return sprintf('%s (count=%d)', $this->getType(), count($value));
166 }
167
168 /**
169 * @return array The raw data structure
170 *
171 * @deprecated since version 3.3. Use array or object access instead.
172 */
173 public function getRawData()
174 {
175 @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the array or object access instead.', __METHOD__));
176
177 return $this->data;
178 }
179
180 /**
181 * Returns a depth limited clone of $this.
182 *
183 * @param int $maxDepth The max dumped depth level
184 *
185 * @return self A clone of $this
186 */
187 public function withMaxDepth($maxDepth)
188 {
189 $data = clone $this;
190 $data->maxDepth = (int) $maxDepth;
191
192 return $data;
193 }
194
195 /**
196 * Limits the number of elements per depth level.
197 *
198 * @param int $maxItemsPerDepth The max number of items dumped per depth level
199 *
200 * @return self A clone of $this
201 */
202 public function withMaxItemsPerDepth($maxItemsPerDepth)
203 {
204 $data = clone $this;
205 $data->maxItemsPerDepth = (int) $maxItemsPerDepth;
206
207 return $data;
208 }
209
210 /**
211 * Enables/disables objects' identifiers tracking.
212 *
213 * @param bool $useRefHandles False to hide global ref. handles
214 *
215 * @return self A clone of $this
216 */
217 public function withRefHandles($useRefHandles)
218 {
219 $data = clone $this;
220 $data->useRefHandles = $useRefHandles ? -1 : 0;
221
222 return $data;
223 }
224
225 /**
226 * Seeks to a specific key in nested data structures.
227 *
228 * @param string|int $key The key to seek to
229 *
230 * @return self|null A clone of $this or null if the key is not set
231 */
232 public function seek($key)
233 {
234 $item = $this->data[$this->position][$this->key];
235
236 if ($item instanceof Stub && Stub::TYPE_REF === $item->type && !$item->position) {
237 $item = $item->value;
238 }
239 if (!($item = $this->getStub($item)) instanceof Stub || !$item->position) {
240 return;
241 }
242 $keys = array($key);
243
244 switch ($item->type) {
245 case Stub::TYPE_OBJECT:
246 $keys[] = Caster::PREFIX_DYNAMIC.$key;
247 $keys[] = Caster::PREFIX_PROTECTED.$key;
248 $keys[] = Caster::PREFIX_VIRTUAL.$key;
249 $keys[] = "\0$item->class\0$key";
250 // no break
251 case Stub::TYPE_ARRAY:
252 case Stub::TYPE_RESOURCE:
253 break;
254 default:
255 return;
256 }
257
258 $data = null;
259 $children = $this->data[$item->position];
260
261 foreach ($keys as $key) {
262 if (isset($children[$key]) || array_key_exists($key, $children)) {
263 $data = clone $this;
264 $data->key = $key;
265 $data->position = $item->position;
266 break;
267 }
268 }
269
270 return $data;
271 }
272
273 /**
274 * Dumps data with a DumperInterface dumper.
275 */
276 public function dump(DumperInterface $dumper)
277 {
278 $refs = array(0);
279 $this->dumpItem($dumper, new Cursor(), $refs, $this->data[$this->position][$this->key]);
280 }
281
282 /**
283 * Depth-first dumping of items.
284 *
285 * @param DumperInterface $dumper The dumper being used for dumping
286 * @param Cursor $cursor A cursor used for tracking dumper state position
287 * @param array &$refs A map of all references discovered while dumping
288 * @param mixed $item A Stub object or the original value being dumped
289 */
290 private function dumpItem($dumper, $cursor, &$refs, $item)
291 {
292 $cursor->refIndex = 0;
293 $cursor->softRefTo = $cursor->softRefHandle = $cursor->softRefCount = 0;
294 $cursor->hardRefTo = $cursor->hardRefHandle = $cursor->hardRefCount = 0;
295 $firstSeen = true;
296
297 if (!$item instanceof Stub) {
298 $cursor->attr = array();
299 $type = \gettype($item);
300 if ($item && 'array' === $type) {
301 $item = $this->getStub($item);
302 }
303 } elseif (Stub::TYPE_REF === $item->type) {
304 if ($item->handle) {
305 if (!isset($refs[$r = $item->handle - (PHP_INT_MAX >> 1)])) {
306 $cursor->refIndex = $refs[$r] = $cursor->refIndex ?: ++$refs[0];
307 } else {
308 $firstSeen = false;
309 }
310 $cursor->hardRefTo = $refs[$r];
311 $cursor->hardRefHandle = $this->useRefHandles & $item->handle;
312 $cursor->hardRefCount = $item->refCount;
313 }
314 $cursor->attr = $item->attr;
315 $type = $item->class ?: gettype($item->value);
316 $item = $this->getStub($item->value);
317 }
318 if ($item instanceof Stub) {
319 if ($item->refCount) {
320 if (!isset($refs[$r = $item->handle])) {
321 $cursor->refIndex = $refs[$r] = $cursor->refIndex ?: ++$refs[0];
322 } else {
323 $firstSeen = false;
324 }
325 $cursor->softRefTo = $refs[$r];
326 }
327 $cursor->softRefHandle = $this->useRefHandles & $item->handle;
328 $cursor->softRefCount = $item->refCount;
329 $cursor->attr = $item->attr;
330 $cut = $item->cut;
331
332 if ($item->position && $firstSeen) {
333 $children = $this->data[$item->position];
334
335 if ($cursor->stop) {
336 if ($cut >= 0) {
337 $cut += count($children);
338 }
339 $children = array();
340 }
341 } else {
342 $children = array();
343 }
344 switch ($item->type) {
345 case Stub::TYPE_STRING:
346 $dumper->dumpString($cursor, $item->value, Stub::STRING_BINARY === $item->class, $cut);
347 break;
348
349 case Stub::TYPE_ARRAY:
350 $item = clone $item;
351 $item->type = $item->class;
352 $item->class = $item->value;
353 // no break
354 case Stub::TYPE_OBJECT:
355 case Stub::TYPE_RESOURCE:
356 $withChildren = $children && $cursor->depth !== $this->maxDepth && $this->maxItemsPerDepth;
357 $dumper->enterHash($cursor, $item->type, $item->class, $withChildren);
358 if ($withChildren) {
359 if ($cursor->skipChildren) {
360 $withChildren = false;
361 $cut = -1;
362 } else {
363 $cut = $this->dumpChildren($dumper, $cursor, $refs, $children, $cut, $item->type, null !== $item->class);
364 }
365 } elseif ($children && 0 <= $cut) {
366 $cut += count($children);
367 }
368 $cursor->skipChildren = false;
369 $dumper->leaveHash($cursor, $item->type, $item->class, $withChildren, $cut);
370 break;
371
372 default:
373 throw new \RuntimeException(sprintf('Unexpected Stub type: %s', $item->type));
374 }
375 } elseif ('array' === $type) {
376 $dumper->enterHash($cursor, Cursor::HASH_INDEXED, 0, false);
377 $dumper->leaveHash($cursor, Cursor::HASH_INDEXED, 0, false, 0);
378 } elseif ('string' === $type) {
379 $dumper->dumpString($cursor, $item, false, 0);
380 } else {
381 $dumper->dumpScalar($cursor, $type, $item);
382 }
383 }
384
385 /**
386 * Dumps children of hash structures.
387 *
388 * @param DumperInterface $dumper
389 * @param Cursor $parentCursor The cursor of the parent hash
390 * @param array &$refs A map of all references discovered while dumping
391 * @param array $children The children to dump
392 * @param int $hashCut The number of items removed from the original hash
393 * @param string $hashType A Cursor::HASH_* const
394 * @param bool $dumpKeys Whether keys should be dumped or not
395 *
396 * @return int The final number of removed items
397 */
398 private function dumpChildren($dumper, $parentCursor, &$refs, $children, $hashCut, $hashType, $dumpKeys)
399 {
400 $cursor = clone $parentCursor;
401 ++$cursor->depth;
402 $cursor->hashType = $hashType;
403 $cursor->hashIndex = 0;
404 $cursor->hashLength = count($children);
405 $cursor->hashCut = $hashCut;
406 foreach ($children as $key => $child) {
407 $cursor->hashKeyIsBinary = isset($key[0]) && !preg_match('//u', $key);
408 $cursor->hashKey = $dumpKeys ? $key : null;
409 $this->dumpItem($dumper, $cursor, $refs, $child);
410 if (++$cursor->hashIndex === $this->maxItemsPerDepth || $cursor->stop) {
411 $parentCursor->stop = true;
412
413 return $hashCut >= 0 ? $hashCut + $cursor->hashLength - $cursor->hashIndex : $hashCut;
414 }
415 }
416
417 return $hashCut;
418 }
419
420 private function getStub($item)
421 {
422 if (!$item || !\is_array($item)) {
423 return $item;
424 }
425
426 $stub = new Stub();
427 $stub->type = Stub::TYPE_ARRAY;
428 foreach ($item as $stub->class => $stub->position) {
429 }
430 if (isset($item[0])) {
431 $stub->cut = $item[0];
432 }
433 $stub->value = $stub->cut + ($stub->position ? \count($this->data[$stub->position]) : 0);
434
435 return $stub;
436 }
437 }