blob: a51cace1d57bd7f9568b169db5860cb605ad6f94 [file] [log] [blame]
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02001<?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
12namespace Symfony\Component\VarDumper\Caster;
13
14use Symfony\Component\VarDumper\Cloner\Stub;
15
16/**
17 * Casts SPL related classes to array representation.
18 *
19 * @author Nicolas Grekas <p@tchwork.com>
20 *
21 * @final
22 */
23class SplCaster
24{
25 private const SPL_FILE_OBJECT_FLAGS = [
26 \SplFileObject::DROP_NEW_LINE => 'DROP_NEW_LINE',
27 \SplFileObject::READ_AHEAD => 'READ_AHEAD',
28 \SplFileObject::SKIP_EMPTY => 'SKIP_EMPTY',
29 \SplFileObject::READ_CSV => 'READ_CSV',
30 ];
31
32 public static function castArrayObject(\ArrayObject $c, array $a, Stub $stub, bool $isNested)
33 {
34 return self::castSplArray($c, $a, $stub, $isNested);
35 }
36
37 public static function castArrayIterator(\ArrayIterator $c, array $a, Stub $stub, bool $isNested)
38 {
39 return self::castSplArray($c, $a, $stub, $isNested);
40 }
41
42 public static function castHeap(\Iterator $c, array $a, Stub $stub, bool $isNested)
43 {
44 $a += [
45 Caster::PREFIX_VIRTUAL.'heap' => iterator_to_array(clone $c),
46 ];
47
48 return $a;
49 }
50
51 public static function castDoublyLinkedList(\SplDoublyLinkedList $c, array $a, Stub $stub, bool $isNested)
52 {
53 $prefix = Caster::PREFIX_VIRTUAL;
54 $mode = $c->getIteratorMode();
55 $c->setIteratorMode(\SplDoublyLinkedList::IT_MODE_KEEP | $mode & ~\SplDoublyLinkedList::IT_MODE_DELETE);
56
57 $a += [
58 $prefix.'mode' => new ConstStub((($mode & \SplDoublyLinkedList::IT_MODE_LIFO) ? 'IT_MODE_LIFO' : 'IT_MODE_FIFO').' | '.(($mode & \SplDoublyLinkedList::IT_MODE_DELETE) ? 'IT_MODE_DELETE' : 'IT_MODE_KEEP'), $mode),
59 $prefix.'dllist' => iterator_to_array($c),
60 ];
61 $c->setIteratorMode($mode);
62
63 return $a;
64 }
65
66 public static function castFileInfo(\SplFileInfo $c, array $a, Stub $stub, bool $isNested)
67 {
68 static $map = [
69 'path' => 'getPath',
70 'filename' => 'getFilename',
71 'basename' => 'getBasename',
72 'pathname' => 'getPathname',
73 'extension' => 'getExtension',
74 'realPath' => 'getRealPath',
75 'aTime' => 'getATime',
76 'mTime' => 'getMTime',
77 'cTime' => 'getCTime',
78 'inode' => 'getInode',
79 'size' => 'getSize',
80 'perms' => 'getPerms',
81 'owner' => 'getOwner',
82 'group' => 'getGroup',
83 'type' => 'getType',
84 'writable' => 'isWritable',
85 'readable' => 'isReadable',
86 'executable' => 'isExecutable',
87 'file' => 'isFile',
88 'dir' => 'isDir',
89 'link' => 'isLink',
90 'linkTarget' => 'getLinkTarget',
91 ];
92
93 $prefix = Caster::PREFIX_VIRTUAL;
94 unset($a["\0SplFileInfo\0fileName"]);
95 unset($a["\0SplFileInfo\0pathName"]);
96
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +010097 try {
98 $c->isReadable();
99 } catch (\RuntimeException $e) {
100 if ('Object not initialized' !== $e->getMessage()) {
101 throw $e;
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200102 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200103
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100104 $a[$prefix.'⚠'] = 'The parent constructor was not called: the object is in an invalid state';
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200105
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100106 return $a;
107 } catch (\Error $e) {
108 if ('Object not initialized' !== $e->getMessage()) {
109 throw $e;
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200110 }
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100111
112 $a[$prefix.'⚠'] = 'The parent constructor was not called: the object is in an invalid state';
113
114 return $a;
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200115 }
116
117 foreach ($map as $key => $accessor) {
118 try {
119 $a[$prefix.$key] = $c->$accessor();
120 } catch (\Exception $e) {
121 }
122 }
123
124 if ($a[$prefix.'realPath'] ?? false) {
125 $a[$prefix.'realPath'] = new LinkStub($a[$prefix.'realPath']);
126 }
127
128 if (isset($a[$prefix.'perms'])) {
129 $a[$prefix.'perms'] = new ConstStub(sprintf('0%o', $a[$prefix.'perms']), $a[$prefix.'perms']);
130 }
131
132 static $mapDate = ['aTime', 'mTime', 'cTime'];
133 foreach ($mapDate as $key) {
134 if (isset($a[$prefix.$key])) {
135 $a[$prefix.$key] = new ConstStub(date('Y-m-d H:i:s', $a[$prefix.$key]), $a[$prefix.$key]);
136 }
137 }
138
139 return $a;
140 }
141
142 public static function castFileObject(\SplFileObject $c, array $a, Stub $stub, bool $isNested)
143 {
144 static $map = [
145 'csvControl' => 'getCsvControl',
146 'flags' => 'getFlags',
147 'maxLineLen' => 'getMaxLineLen',
148 'fstat' => 'fstat',
149 'eof' => 'eof',
150 'key' => 'key',
151 ];
152
153 $prefix = Caster::PREFIX_VIRTUAL;
154
155 foreach ($map as $key => $accessor) {
156 try {
157 $a[$prefix.$key] = $c->$accessor();
158 } catch (\Exception $e) {
159 }
160 }
161
162 if (isset($a[$prefix.'flags'])) {
163 $flagsArray = [];
164 foreach (self::SPL_FILE_OBJECT_FLAGS as $value => $name) {
165 if ($a[$prefix.'flags'] & $value) {
166 $flagsArray[] = $name;
167 }
168 }
169 $a[$prefix.'flags'] = new ConstStub(implode('|', $flagsArray), $a[$prefix.'flags']);
170 }
171
172 if (isset($a[$prefix.'fstat'])) {
173 $a[$prefix.'fstat'] = new CutArrayStub($a[$prefix.'fstat'], ['dev', 'ino', 'nlink', 'rdev', 'blksize', 'blocks']);
174 }
175
176 return $a;
177 }
178
179 public static function castObjectStorage(\SplObjectStorage $c, array $a, Stub $stub, bool $isNested)
180 {
181 $storage = [];
182 unset($a[Caster::PREFIX_DYNAMIC."\0gcdata"]); // Don't hit https://bugs.php.net/65967
183 unset($a["\0SplObjectStorage\0storage"]);
184
185 $clone = clone $c;
186 foreach ($clone as $obj) {
187 $storage[] = [
188 'object' => $obj,
189 'info' => $clone->getInfo(),
190 ];
191 }
192
193 $a += [
194 Caster::PREFIX_VIRTUAL.'storage' => $storage,
195 ];
196
197 return $a;
198 }
199
200 public static function castOuterIterator(\OuterIterator $c, array $a, Stub $stub, bool $isNested)
201 {
202 $a[Caster::PREFIX_VIRTUAL.'innerIterator'] = $c->getInnerIterator();
203
204 return $a;
205 }
206
207 public static function castWeakReference(\WeakReference $c, array $a, Stub $stub, bool $isNested)
208 {
209 $a[Caster::PREFIX_VIRTUAL.'object'] = $c->get();
210
211 return $a;
212 }
213
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100214 private static function castSplArray(\ArrayObject|\ArrayIterator $c, array $a, Stub $stub, bool $isNested): array
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200215 {
216 $prefix = Caster::PREFIX_VIRTUAL;
217 $flags = $c->getFlags();
218
219 if (!($flags & \ArrayObject::STD_PROP_LIST)) {
220 $c->setFlags(\ArrayObject::STD_PROP_LIST);
221 $a = Caster::castObject($c, \get_class($c), method_exists($c, '__debugInfo'), $stub->class);
222 $c->setFlags($flags);
223 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200224 $a += [
225 $prefix.'flag::STD_PROP_LIST' => (bool) ($flags & \ArrayObject::STD_PROP_LIST),
226 $prefix.'flag::ARRAY_AS_PROPS' => (bool) ($flags & \ArrayObject::ARRAY_AS_PROPS),
227 ];
228 if ($c instanceof \ArrayObject) {
229 $a[$prefix.'iteratorClass'] = new ClassStub($c->getIteratorClass());
230 }
231
232 return $a;
233 }
234}