PluginProbe ʕ •ᴥ•ʔ
Kubio AI Page Builder / trunk
Kubio AI Page Builder vtrunk
2.9.0 2.8.6 2.8.5 2.8.4 2.8.3 2.8.2 2.8.1 trunk 1.0.0 1.0.1 1.1.0 1.2.0 1.2.1 1.2.2 1.2.3 1.3.0 1.3.1 1.3.2 1.4.0 1.4.1 1.4.2 1.4.3 1.5.0 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.7.0 1.7.1 1.7.2 1.7.3 1.8.0 1.8.1 1.8.2 1.9.0 2.0.0 2.1.1 2.1.2 2.1.3 2.2.0 2.2.3 2.2.4 2.2.5 2.3.0 2.3.1 2.3.3 2.3.4 2.4.0 2.4.1 2.4.2 2.4.3 2.4.5 2.5.0 2.5.1 2.5.2 2.5.3 2.6.0 2.6.1 2.6.2 2.6.3 2.6.5 2.6.6 2.6.7 2.7.0 2.7.1 2.7.2 2.7.3 2.8.0
kubio / vendor / symfony / var-dumper / Cloner / Data.php
kubio / vendor / symfony / var-dumper / Cloner Last commit date
AbstractCloner.php 1 year ago ClonerInterface.php 1 year ago Cursor.php 4 years ago Data.php 1 year ago DumperInterface.php 1 year ago Stub.php 4 years ago VarCloner.php 1 year ago
Data.php
469 lines
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\Dumper\ContextProvider\SourceContextProvider;
16
17 /**
18 * @author Nicolas Grekas <p@tchwork.com>
19 */
20 class Data implements \ArrayAccess, \Countable, \IteratorAggregate
21 {
22 private $data;
23 private $position = 0;
24 private $key = 0;
25 private $maxDepth = 20;
26 private $maxItemsPerDepth = -1;
27 private $useRefHandles = -1;
28 private $context = [];
29
30 /**
31 * @param array $data An array as returned by ClonerInterface::cloneVar()
32 */
33 public function __construct(array $data)
34 {
35 $this->data = $data;
36 }
37
38 /**
39 * @return string|null
40 */
41 public function getType()
42 {
43 $item = $this->data[$this->position][$this->key];
44
45 if ($item instanceof Stub && Stub::TYPE_REF === $item->type && !$item->position) {
46 $item = $item->value;
47 }
48 if (!$item instanceof Stub) {
49 return \gettype($item);
50 }
51 if (Stub::TYPE_STRING === $item->type) {
52 return 'string';
53 }
54 if (Stub::TYPE_ARRAY === $item->type) {
55 return 'array';
56 }
57 if (Stub::TYPE_OBJECT === $item->type) {
58 return $item->class;
59 }
60 if (Stub::TYPE_RESOURCE === $item->type) {
61 return $item->class.' resource';
62 }
63
64 return null;
65 }
66
67 /**
68 * Returns a native representation of the original value.
69 *
70 * @param array|bool $recursive Whether values should be resolved recursively or not
71 *
72 * @return string|int|float|bool|array|Data[]|null
73 */
74 public function getValue($recursive = false)
75 {
76 $item = $this->data[$this->position][$this->key];
77
78 if ($item instanceof Stub && Stub::TYPE_REF === $item->type && !$item->position) {
79 $item = $item->value;
80 }
81 if (!($item = $this->getStub($item)) instanceof Stub) {
82 return $item;
83 }
84 if (Stub::TYPE_STRING === $item->type) {
85 return $item->value;
86 }
87
88 $children = $item->position ? $this->data[$item->position] : [];
89
90 foreach ($children as $k => $v) {
91 if ($recursive && !($v = $this->getStub($v)) instanceof Stub) {
92 continue;
93 }
94 $children[$k] = clone $this;
95 $children[$k]->key = $k;
96 $children[$k]->position = $item->position;
97
98 if ($recursive) {
99 if (Stub::TYPE_REF === $v->type && ($v = $this->getStub($v->value)) instanceof Stub) {
100 $recursive = (array) $recursive;
101 if (isset($recursive[$v->position])) {
102 continue;
103 }
104 $recursive[$v->position] = true;
105 }
106 $children[$k] = $children[$k]->getValue($recursive);
107 }
108 }
109
110 return $children;
111 }
112
113 /**
114 * @return int
115 */
116 #[\ReturnTypeWillChange]
117 public function count()
118 {
119 return \count($this->getValue());
120 }
121
122 /**
123 * @return \Traversable
124 */
125 #[\ReturnTypeWillChange]
126 public function getIterator()
127 {
128 if (!\is_array($value = $this->getValue())) {
129 throw new \LogicException(sprintf('"%s" object holds non-iterable type "%s".', self::class, get_debug_type($value)));
130 }
131
132 yield from $value;
133 }
134
135 public function __get(string $key)
136 {
137 if (null !== $data = $this->seek($key)) {
138 $item = $this->getStub($data->data[$data->position][$data->key]);
139
140 return $item instanceof Stub || [] === $item ? $data : $item;
141 }
142
143 return null;
144 }
145
146 /**
147 * @return bool
148 */
149 public function __isset(string $key)
150 {
151 return null !== $this->seek($key);
152 }
153
154 /**
155 * @return bool
156 */
157 #[\ReturnTypeWillChange]
158 public function offsetExists($key)
159 {
160 return $this->__isset($key);
161 }
162
163 /**
164 * @return mixed
165 */
166 #[\ReturnTypeWillChange]
167 public function offsetGet($key)
168 {
169 return $this->__get($key);
170 }
171
172 /**
173 * @return void
174 */
175 #[\ReturnTypeWillChange]
176 public function offsetSet($key, $value)
177 {
178 throw new \BadMethodCallException(self::class.' objects are immutable.');
179 }
180
181 /**
182 * @return void
183 */
184 #[\ReturnTypeWillChange]
185 public function offsetUnset($key)
186 {
187 throw new \BadMethodCallException(self::class.' objects are immutable.');
188 }
189
190 /**
191 * @return string
192 */
193 public function __toString()
194 {
195 $value = $this->getValue();
196
197 if (!\is_array($value)) {
198 return (string) $value;
199 }
200
201 return sprintf('%s (count=%d)', $this->getType(), \count($value));
202 }
203
204 /**
205 * Returns a depth limited clone of $this.
206 *
207 * @return static
208 */
209 public function withMaxDepth(int $maxDepth)
210 {
211 $data = clone $this;
212 $data->maxDepth = $maxDepth;
213
214 return $data;
215 }
216
217 /**
218 * Limits the number of elements per depth level.
219 *
220 * @return static
221 */
222 public function withMaxItemsPerDepth(int $maxItemsPerDepth)
223 {
224 $data = clone $this;
225 $data->maxItemsPerDepth = $maxItemsPerDepth;
226
227 return $data;
228 }
229
230 /**
231 * Enables/disables objects' identifiers tracking.
232 *
233 * @param bool $useRefHandles False to hide global ref. handles
234 *
235 * @return static
236 */
237 public function withRefHandles(bool $useRefHandles)
238 {
239 $data = clone $this;
240 $data->useRefHandles = $useRefHandles ? -1 : 0;
241
242 return $data;
243 }
244
245 /**
246 * @return static
247 */
248 public function withContext(array $context)
249 {
250 $data = clone $this;
251 $data->context = $context;
252
253 return $data;
254 }
255
256 /**
257 * Seeks to a specific key in nested data structures.
258 *
259 * @param string|int $key The key to seek to
260 *
261 * @return static|null
262 */
263 public function seek($key)
264 {
265 $item = $this->data[$this->position][$this->key];
266
267 if ($item instanceof Stub && Stub::TYPE_REF === $item->type && !$item->position) {
268 $item = $item->value;
269 }
270 if (!($item = $this->getStub($item)) instanceof Stub || !$item->position) {
271 return null;
272 }
273 $keys = [$key];
274
275 switch ($item->type) {
276 case Stub::TYPE_OBJECT:
277 $keys[] = Caster::PREFIX_DYNAMIC.$key;
278 $keys[] = Caster::PREFIX_PROTECTED.$key;
279 $keys[] = Caster::PREFIX_VIRTUAL.$key;
280 $keys[] = "\0$item->class\0$key";
281 // no break
282 case Stub::TYPE_ARRAY:
283 case Stub::TYPE_RESOURCE:
284 break;
285 default:
286 return null;
287 }
288
289 $data = null;
290 $children = $this->data[$item->position];
291
292 foreach ($keys as $key) {
293 if (isset($children[$key]) || \array_key_exists($key, $children)) {
294 $data = clone $this;
295 $data->key = $key;
296 $data->position = $item->position;
297 break;
298 }
299 }
300
301 return $data;
302 }
303
304 /**
305 * Dumps data with a DumperInterface dumper.
306 */
307 public function dump(DumperInterface $dumper)
308 {
309 $refs = [0];
310 $cursor = new Cursor();
311
312 if ($cursor->attr = $this->context[SourceContextProvider::class] ?? []) {
313 $cursor->attr['if_links'] = true;
314 $cursor->hashType = -1;
315 $dumper->dumpScalar($cursor, 'default', '^');
316 $cursor->attr = ['if_links' => true];
317 $dumper->dumpScalar($cursor, 'default', ' ');
318 $cursor->hashType = 0;
319 }
320
321 $this->dumpItem($dumper, $cursor, $refs, $this->data[$this->position][$this->key]);
322 }
323
324 /**
325 * Depth-first dumping of items.
326 *
327 * @param mixed $item A Stub object or the original value being dumped
328 */
329 private function dumpItem(DumperInterface $dumper, Cursor $cursor, array &$refs, $item)
330 {
331 $cursor->refIndex = 0;
332 $cursor->softRefTo = $cursor->softRefHandle = $cursor->softRefCount = 0;
333 $cursor->hardRefTo = $cursor->hardRefHandle = $cursor->hardRefCount = 0;
334 $firstSeen = true;
335
336 if (!$item instanceof Stub) {
337 $cursor->attr = [];
338 $type = \gettype($item);
339 if ($item && 'array' === $type) {
340 $item = $this->getStub($item);
341 }
342 } elseif (Stub::TYPE_REF === $item->type) {
343 if ($item->handle) {
344 if (!isset($refs[$r = $item->handle - (\PHP_INT_MAX >> 1)])) {
345 $cursor->refIndex = $refs[$r] = $cursor->refIndex ?: ++$refs[0];
346 } else {
347 $firstSeen = false;
348 }
349 $cursor->hardRefTo = $refs[$r];
350 $cursor->hardRefHandle = $this->useRefHandles & $item->handle;
351 $cursor->hardRefCount = 0 < $item->handle ? $item->refCount : 0;
352 }
353 $cursor->attr = $item->attr;
354 $type = $item->class ?: \gettype($item->value);
355 $item = $this->getStub($item->value);
356 }
357 if ($item instanceof Stub) {
358 if ($item->refCount) {
359 if (!isset($refs[$r = $item->handle])) {
360 $cursor->refIndex = $refs[$r] = $cursor->refIndex ?: ++$refs[0];
361 } else {
362 $firstSeen = false;
363 }
364 $cursor->softRefTo = $refs[$r];
365 }
366 $cursor->softRefHandle = $this->useRefHandles & $item->handle;
367 $cursor->softRefCount = $item->refCount;
368 $cursor->attr = $item->attr;
369 $cut = $item->cut;
370
371 if ($item->position && $firstSeen) {
372 $children = $this->data[$item->position];
373
374 if ($cursor->stop) {
375 if ($cut >= 0) {
376 $cut += \count($children);
377 }
378 $children = [];
379 }
380 } else {
381 $children = [];
382 }
383 switch ($item->type) {
384 case Stub::TYPE_STRING:
385 $dumper->dumpString($cursor, $item->value, Stub::STRING_BINARY === $item->class, $cut);
386 break;
387
388 case Stub::TYPE_ARRAY:
389 $item = clone $item;
390 $item->type = $item->class;
391 $item->class = $item->value;
392 // no break
393 case Stub::TYPE_OBJECT:
394 case Stub::TYPE_RESOURCE:
395 $withChildren = $children && $cursor->depth !== $this->maxDepth && $this->maxItemsPerDepth;
396 $dumper->enterHash($cursor, $item->type, $item->class, $withChildren);
397 if ($withChildren) {
398 if ($cursor->skipChildren) {
399 $withChildren = false;
400 $cut = -1;
401 } else {
402 $cut = $this->dumpChildren($dumper, $cursor, $refs, $children, $cut, $item->type, null !== $item->class);
403 }
404 } elseif ($children && 0 <= $cut) {
405 $cut += \count($children);
406 }
407 $cursor->skipChildren = false;
408 $dumper->leaveHash($cursor, $item->type, $item->class, $withChildren, $cut);
409 break;
410
411 default:
412 throw new \RuntimeException(sprintf('Unexpected Stub type: "%s".', $item->type));
413 }
414 } elseif ('array' === $type) {
415 $dumper->enterHash($cursor, Cursor::HASH_INDEXED, 0, false);
416 $dumper->leaveHash($cursor, Cursor::HASH_INDEXED, 0, false, 0);
417 } elseif ('string' === $type) {
418 $dumper->dumpString($cursor, $item, false, 0);
419 } else {
420 $dumper->dumpScalar($cursor, $type, $item);
421 }
422 }
423
424 /**
425 * Dumps children of hash structures.
426 *
427 * @return int The final number of removed items
428 */
429 private function dumpChildren(DumperInterface $dumper, Cursor $parentCursor, array &$refs, array $children, int $hashCut, int $hashType, bool $dumpKeys): int
430 {
431 $cursor = clone $parentCursor;
432 ++$cursor->depth;
433 $cursor->hashType = $hashType;
434 $cursor->hashIndex = 0;
435 $cursor->hashLength = \count($children);
436 $cursor->hashCut = $hashCut;
437 foreach ($children as $key => $child) {
438 $cursor->hashKeyIsBinary = isset($key[0]) && !preg_match('//u', $key);
439 $cursor->hashKey = $dumpKeys ? $key : null;
440 $this->dumpItem($dumper, $cursor, $refs, $child);
441 if (++$cursor->hashIndex === $this->maxItemsPerDepth || $cursor->stop) {
442 $parentCursor->stop = true;
443
444 return $hashCut >= 0 ? $hashCut + $cursor->hashLength - $cursor->hashIndex : $hashCut;
445 }
446 }
447
448 return $hashCut;
449 }
450
451 private function getStub($item)
452 {
453 if (!$item || !\is_array($item)) {
454 return $item;
455 }
456
457 $stub = new Stub();
458 $stub->type = Stub::TYPE_ARRAY;
459 foreach ($item as $stub->class => $stub->position) {
460 }
461 if (isset($item[0])) {
462 $stub->cut = $item[0];
463 }
464 $stub->value = $stub->cut + ($stub->position ? \count($this->data[$stub->position]) : 0);
465
466 return $stub;
467 }
468 }
469