Mercurial > hg > cmmr2012-drupal-site
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 } |