PluginProbe ʕ •ᴥ•ʔ
Kubio AI Page Builder / 2.8.6
Kubio AI Page Builder v2.8.6
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 / VarCloner.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
VarCloner.php
312 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 /**
15 * @author Nicolas Grekas <p@tchwork.com>
16 */
17 class VarCloner extends AbstractCloner
18 {
19 private static $gid;
20 private static $arrayCache = [];
21
22 /**
23 * {@inheritdoc}
24 */
25 protected function doClone($var)
26 {
27 $len = 1; // Length of $queue
28 $pos = 0; // Number of cloned items past the minimum depth
29 $refsCounter = 0; // Hard references counter
30 $queue = [[$var]]; // This breadth-first queue is the return value
31 $hardRefs = []; // Map of original zval ids to stub objects
32 $objRefs = []; // Map of original object handles to their stub object counterpart
33 $objects = []; // Keep a ref to objects to ensure their handle cannot be reused while cloning
34 $resRefs = []; // Map of original resource handles to their stub object counterpart
35 $values = []; // Map of stub objects' ids to original values
36 $maxItems = $this->maxItems;
37 $maxString = $this->maxString;
38 $minDepth = $this->minDepth;
39 $currentDepth = 0; // Current tree depth
40 $currentDepthFinalIndex = 0; // Final $queue index for current tree depth
41 $minimumDepthReached = 0 === $minDepth; // Becomes true when minimum tree depth has been reached
42 $cookie = (object) []; // Unique object used to detect hard references
43 $a = null; // Array cast for nested structures
44 $stub = null; // Stub capturing the main properties of an original item value
45 // or null if the original value is used directly
46
47 if (!$gid = self::$gid) {
48 $gid = self::$gid = md5(random_bytes(6)); // Unique string used to detect the special $GLOBALS variable
49 }
50 $arrayStub = new Stub();
51 $arrayStub->type = Stub::TYPE_ARRAY;
52 $fromObjCast = false;
53
54 for ($i = 0; $i < $len; ++$i) {
55 // Detect when we move on to the next tree depth
56 if ($i > $currentDepthFinalIndex) {
57 ++$currentDepth;
58 $currentDepthFinalIndex = $len - 1;
59 if ($currentDepth >= $minDepth) {
60 $minimumDepthReached = true;
61 }
62 }
63
64 $refs = $vals = $queue[$i];
65 foreach ($vals as $k => $v) {
66 // $v is the original value or a stub object in case of hard references
67
68 if (\PHP_VERSION_ID >= 70400) {
69 $zvalRef = ($r = \ReflectionReference::fromArrayElement($vals, $k)) ? $r->getId() : null;
70 } else {
71 $refs[$k] = $cookie;
72 $zvalRef = $vals[$k] === $cookie;
73 }
74
75 if ($zvalRef) {
76 $vals[$k] = &$stub; // Break hard references to make $queue completely
77 unset($stub); // independent from the original structure
78 if (\PHP_VERSION_ID >= 70400 ? null !== $vals[$k] = $hardRefs[$zvalRef] ?? null : $v instanceof Stub && isset($hardRefs[spl_object_id($v)])) {
79 if (\PHP_VERSION_ID >= 70400) {
80 $v = $vals[$k];
81 } else {
82 $refs[$k] = $vals[$k] = $v;
83 }
84 if ($v->value instanceof Stub && (Stub::TYPE_OBJECT === $v->value->type || Stub::TYPE_RESOURCE === $v->value->type)) {
85 ++$v->value->refCount;
86 }
87 ++$v->refCount;
88 continue;
89 }
90 $vals[$k] = new Stub();
91 $vals[$k]->value = $v;
92 $vals[$k]->handle = ++$refsCounter;
93
94 if (\PHP_VERSION_ID >= 70400) {
95 $hardRefs[$zvalRef] = $vals[$k];
96 } else {
97 $refs[$k] = $vals[$k];
98 $h = spl_object_id($refs[$k]);
99 $hardRefs[$h] = &$refs[$k];
100 $values[$h] = $v;
101 }
102 }
103 // Create $stub when the original value $v cannot be used directly
104 // If $v is a nested structure, put that structure in array $a
105 switch (true) {
106 case null === $v:
107 case \is_bool($v):
108 case \is_int($v):
109 case \is_float($v):
110 continue 2;
111 case \is_string($v):
112 if ('' === $v) {
113 continue 2;
114 }
115 if (!preg_match('//u', $v)) {
116 $stub = new Stub();
117 $stub->type = Stub::TYPE_STRING;
118 $stub->class = Stub::STRING_BINARY;
119 if (0 <= $maxString && 0 < $cut = \strlen($v) - $maxString) {
120 $stub->cut = $cut;
121 $stub->value = substr($v, 0, -$cut);
122 } else {
123 $stub->value = $v;
124 }
125 } elseif (0 <= $maxString && isset($v[1 + ($maxString >> 2)]) && 0 < $cut = mb_strlen($v, 'UTF-8') - $maxString) {
126 $stub = new Stub();
127 $stub->type = Stub::TYPE_STRING;
128 $stub->class = Stub::STRING_UTF8;
129 $stub->cut = $cut;
130 $stub->value = mb_substr($v, 0, $maxString, 'UTF-8');
131 } else {
132 continue 2;
133 }
134 $a = null;
135 break;
136
137 case \is_array($v):
138 if (!$v) {
139 continue 2;
140 }
141 $stub = $arrayStub;
142
143 if (\PHP_VERSION_ID >= 80100) {
144 $stub->class = array_is_list($v) ? Stub::ARRAY_INDEXED : Stub::ARRAY_ASSOC;
145 $a = $v;
146 break;
147 }
148
149 $stub->class = Stub::ARRAY_INDEXED;
150
151 $j = -1;
152 foreach ($v as $gk => $gv) {
153 if ($gk !== ++$j) {
154 $stub->class = Stub::ARRAY_ASSOC;
155 $a = $v;
156 $a[$gid] = true;
157 break;
158 }
159 }
160
161 // Copies of $GLOBALS have very strange behavior,
162 // let's detect them with some black magic
163 if (isset($v[$gid])) {
164 unset($v[$gid]);
165 $a = [];
166 foreach ($v as $gk => &$gv) {
167 if ($v === $gv && (\PHP_VERSION_ID < 70400 || !isset($hardRefs[\ReflectionReference::fromArrayElement($v, $gk)->getId()]))) {
168 unset($v);
169 $v = new Stub();
170 $v->value = [$v->cut = \count($gv), Stub::TYPE_ARRAY => 0];
171 $v->handle = -1;
172 if (\PHP_VERSION_ID >= 70400) {
173 $gv = &$a[$gk];
174 $hardRefs[\ReflectionReference::fromArrayElement($a, $gk)->getId()] = &$gv;
175 } else {
176 $gv = &$hardRefs[spl_object_id($v)];
177 }
178 $gv = $v;
179 }
180
181 $a[$gk] = &$gv;
182 }
183 unset($gv);
184 } else {
185 $a = $v;
186 }
187 break;
188
189 case \is_object($v):
190 if (empty($objRefs[$h = spl_object_id($v)])) {
191 $stub = new Stub();
192 $stub->type = Stub::TYPE_OBJECT;
193 $stub->class = \get_class($v);
194 $stub->value = $v;
195 $stub->handle = $h;
196 $a = $this->castObject($stub, 0 < $i);
197 if ($v !== $stub->value) {
198 if (Stub::TYPE_OBJECT !== $stub->type || null === $stub->value) {
199 break;
200 }
201 $stub->handle = $h = spl_object_id($stub->value);
202 }
203 $stub->value = null;
204 if (0 <= $maxItems && $maxItems <= $pos && $minimumDepthReached) {
205 $stub->cut = \count($a);
206 $a = null;
207 }
208 }
209 if (empty($objRefs[$h])) {
210 $objRefs[$h] = $stub;
211 $objects[] = $v;
212 } else {
213 $stub = $objRefs[$h];
214 ++$stub->refCount;
215 $a = null;
216 }
217 break;
218
219 default: // resource
220 if (empty($resRefs[$h = (int) $v])) {
221 $stub = new Stub();
222 $stub->type = Stub::TYPE_RESOURCE;
223 if ('Unknown' === $stub->class = @get_resource_type($v)) {
224 $stub->class = 'Closed';
225 }
226 $stub->value = $v;
227 $stub->handle = $h;
228 $a = $this->castResource($stub, 0 < $i);
229 $stub->value = null;
230 if (0 <= $maxItems && $maxItems <= $pos && $minimumDepthReached) {
231 $stub->cut = \count($a);
232 $a = null;
233 }
234 }
235 if (empty($resRefs[$h])) {
236 $resRefs[$h] = $stub;
237 } else {
238 $stub = $resRefs[$h];
239 ++$stub->refCount;
240 $a = null;
241 }
242 break;
243 }
244
245 if ($a) {
246 if (!$minimumDepthReached || 0 > $maxItems) {
247 $queue[$len] = $a;
248 $stub->position = $len++;
249 } elseif ($pos < $maxItems) {
250 if ($maxItems < $pos += \count($a)) {
251 $a = \array_slice($a, 0, $maxItems - $pos, true);
252 if ($stub->cut >= 0) {
253 $stub->cut += $pos - $maxItems;
254 }
255 }
256 $queue[$len] = $a;
257 $stub->position = $len++;
258 } elseif ($stub->cut >= 0) {
259 $stub->cut += \count($a);
260 $stub->position = 0;
261 }
262 }
263
264 if ($arrayStub === $stub) {
265 if ($arrayStub->cut) {
266 $stub = [$arrayStub->cut, $arrayStub->class => $arrayStub->position];
267 $arrayStub->cut = 0;
268 } elseif (isset(self::$arrayCache[$arrayStub->class][$arrayStub->position])) {
269 $stub = self::$arrayCache[$arrayStub->class][$arrayStub->position];
270 } else {
271 self::$arrayCache[$arrayStub->class][$arrayStub->position] = $stub = [$arrayStub->class => $arrayStub->position];
272 }
273 }
274
275 if (!$zvalRef) {
276 $vals[$k] = $stub;
277 } elseif (\PHP_VERSION_ID >= 70400) {
278 $hardRefs[$zvalRef]->value = $stub;
279 } else {
280 $refs[$k]->value = $stub;
281 }
282 }
283
284 if ($fromObjCast) {
285 $fromObjCast = false;
286 $refs = $vals;
287 $vals = [];
288 $j = -1;
289 foreach ($queue[$i] as $k => $v) {
290 foreach ([$k => true] as $gk => $gv) {
291 }
292 if ($gk !== $k) {
293 $vals = (object) $vals;
294 $vals->{$k} = $refs[++$j];
295 $vals = (array) $vals;
296 } else {
297 $vals[$k] = $refs[++$j];
298 }
299 }
300 }
301
302 $queue[$i] = $vals;
303 }
304
305 foreach ($values as $h => $v) {
306 $hardRefs[$h] = $v;
307 }
308
309 return $queue;
310 }
311 }
312