blob: 07f445116f660d2299c37932ae58b382f1caaa55 [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
97 if (\PHP_VERSION_ID < 80000) {
98 if (false === $c->getPathname()) {
99 $a[$prefix.'⚠'] = 'The parent constructor was not called: the object is in an invalid state';
100
101 return $a;
102 }
103 } else {
104 try {
105 $c->isReadable();
106 } catch (\RuntimeException $e) {
107 if ('Object not initialized' !== $e->getMessage()) {
108 throw $e;
109 }
110
111 $a[$prefix.'⚠'] = 'The parent constructor was not called: the object is in an invalid state';
112
113 return $a;
114 } catch (\Error $e) {
115 if ('Object not initialized' !== $e->getMessage()) {
116 throw $e;
117 }
118
119 $a[$prefix.'⚠'] = 'The parent constructor was not called: the object is in an invalid state';
120
121 return $a;
122 }
123 }
124
125 foreach ($map as $key => $accessor) {
126 try {
127 $a[$prefix.$key] = $c->$accessor();
128 } catch (\Exception $e) {
129 }
130 }
131
132 if ($a[$prefix.'realPath'] ?? false) {
133 $a[$prefix.'realPath'] = new LinkStub($a[$prefix.'realPath']);
134 }
135
136 if (isset($a[$prefix.'perms'])) {
137 $a[$prefix.'perms'] = new ConstStub(sprintf('0%o', $a[$prefix.'perms']), $a[$prefix.'perms']);
138 }
139
140 static $mapDate = ['aTime', 'mTime', 'cTime'];
141 foreach ($mapDate as $key) {
142 if (isset($a[$prefix.$key])) {
143 $a[$prefix.$key] = new ConstStub(date('Y-m-d H:i:s', $a[$prefix.$key]), $a[$prefix.$key]);
144 }
145 }
146
147 return $a;
148 }
149
150 public static function castFileObject(\SplFileObject $c, array $a, Stub $stub, bool $isNested)
151 {
152 static $map = [
153 'csvControl' => 'getCsvControl',
154 'flags' => 'getFlags',
155 'maxLineLen' => 'getMaxLineLen',
156 'fstat' => 'fstat',
157 'eof' => 'eof',
158 'key' => 'key',
159 ];
160
161 $prefix = Caster::PREFIX_VIRTUAL;
162
163 foreach ($map as $key => $accessor) {
164 try {
165 $a[$prefix.$key] = $c->$accessor();
166 } catch (\Exception $e) {
167 }
168 }
169
170 if (isset($a[$prefix.'flags'])) {
171 $flagsArray = [];
172 foreach (self::SPL_FILE_OBJECT_FLAGS as $value => $name) {
173 if ($a[$prefix.'flags'] & $value) {
174 $flagsArray[] = $name;
175 }
176 }
177 $a[$prefix.'flags'] = new ConstStub(implode('|', $flagsArray), $a[$prefix.'flags']);
178 }
179
180 if (isset($a[$prefix.'fstat'])) {
181 $a[$prefix.'fstat'] = new CutArrayStub($a[$prefix.'fstat'], ['dev', 'ino', 'nlink', 'rdev', 'blksize', 'blocks']);
182 }
183
184 return $a;
185 }
186
187 public static function castObjectStorage(\SplObjectStorage $c, array $a, Stub $stub, bool $isNested)
188 {
189 $storage = [];
190 unset($a[Caster::PREFIX_DYNAMIC."\0gcdata"]); // Don't hit https://bugs.php.net/65967
191 unset($a["\0SplObjectStorage\0storage"]);
192
193 $clone = clone $c;
194 foreach ($clone as $obj) {
195 $storage[] = [
196 'object' => $obj,
197 'info' => $clone->getInfo(),
198 ];
199 }
200
201 $a += [
202 Caster::PREFIX_VIRTUAL.'storage' => $storage,
203 ];
204
205 return $a;
206 }
207
208 public static function castOuterIterator(\OuterIterator $c, array $a, Stub $stub, bool $isNested)
209 {
210 $a[Caster::PREFIX_VIRTUAL.'innerIterator'] = $c->getInnerIterator();
211
212 return $a;
213 }
214
215 public static function castWeakReference(\WeakReference $c, array $a, Stub $stub, bool $isNested)
216 {
217 $a[Caster::PREFIX_VIRTUAL.'object'] = $c->get();
218
219 return $a;
220 }
221
222 private static function castSplArray($c, array $a, Stub $stub, bool $isNested): array
223 {
224 $prefix = Caster::PREFIX_VIRTUAL;
225 $flags = $c->getFlags();
226
227 if (!($flags & \ArrayObject::STD_PROP_LIST)) {
228 $c->setFlags(\ArrayObject::STD_PROP_LIST);
229 $a = Caster::castObject($c, \get_class($c), method_exists($c, '__debugInfo'), $stub->class);
230 $c->setFlags($flags);
231 }
232 if (\PHP_VERSION_ID < 70400) {
233 $a[$prefix.'storage'] = $c->getArrayCopy();
234 }
235 $a += [
236 $prefix.'flag::STD_PROP_LIST' => (bool) ($flags & \ArrayObject::STD_PROP_LIST),
237 $prefix.'flag::ARRAY_AS_PROPS' => (bool) ($flags & \ArrayObject::ARRAY_AS_PROPS),
238 ];
239 if ($c instanceof \ArrayObject) {
240 $a[$prefix.'iteratorClass'] = new ClassStub($c->getIteratorClass());
241 }
242
243 return $a;
244 }
245}