8000 [VarDumper] symfony_debug ext. fast and memory efficient cloning algo · symfony/symfony@5b7ae28 · GitHub
[go: up one dir, main page]

Skip to content

Commit 5b7ae28

Browse files
[VarDumper] symfony_debug ext. fast and memory efficient cloning algo
1 parent 07135a0 commit 5b7ae28

File tree

1 file changed

+171
-0
lines changed

1 file changed

+171
-0
lines changed
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
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 ExtCloner extends AbstractCloner
18+
{
19+
/**
20+
* {@inheritdoc}
21+
*/
22+
protected function doClone($var)
23+
{
24+
$i = 0; // Current iteration position in $queue
25+
$len = 1; // Length of $queue
26+
$pos = 0; // Number of cloned items past the first level
27+
$refs = 0; // Number of hard+soft references in $var
28+
$queue = array(array($var)); // This breadth-first queue is the return value
29+
$arrayRefs = array(); // Map of queue indexes to stub array objects
30+
$hardRefs = array(); // Map of original zval hashes to stub objects
31+
$softRefs = array(); // Map of original object hashes to their stub object couterpart
32+
$maxItems = $this->maxItems;
33+
$maxString = $this->maxString;
34+
$a = null; // Array cast for nested structures
35+
$stub = null; // stdClass capturing the main properties of an original item value,
36+
// or null if the original value is used directly
37+
38+
for ($i = 0; $i < $len; ++$i) {
39+
$indexed = true; // Whether the currently iterated array is numerically indexed or not
40+
$j = -1; // Position in the currently iterated array
41+
$step = $queue[$i]; // Copy of the currently iterated array used for hard references detection
42+
foreach ($step as $k => $v) {
43+
// $k is the original key
44+
// $v is the original value or a stub object in case of hard references
45+
if ($indexed && $k !== ++$j) {
46+
$indexed = false;
47+
}
48+
$zval = symfony_zval_info($k, $step);
49+
if ($zval['zval_isref']) {
50+
$queue[$i][$k] =& $stub; // Break hard references to make $queue completely
51+
unset($stub); // independent from the original structure
52+
if (isset($hardRefs[$h = $zval['zval_hash']])) {
53+
$hardRefs[$h]->ref = ++$refs;
54+
$queue[$i][$k] = $hardRefs[$h];
55+
continue;
56+
}
57+
}
58+
// Create $stub when the original value $v can not be used directly
59+
// If $v is a nested structure, put that structure in array $a
60+
switch ($zval['type']) {
61+
case 'string':
62+
if (isset($v[0]) && !preg_match('//u', $v)) {
63+
if (0 <= $maxString && 0 < $cut = strlen($v) - $maxString) {
64+
$stub = substr_replace($v, '', -$cut);
65+
$stub = (object) array('cut' => $cut, 'bin' => Data::utf8Encode($stub));
66+
} else {
67+
$stub = (object) array('bin' => Data::utf8Encode($v));
68+
}
69+
} elseif (0 <= $maxString && isset($v[1+($maxString>>2)]) && 0 < $cut = iconv_strlen($v, 'UTF-8') - $maxString) {
70+
$stub = iconv_substr($v, 0, $maxString, 'UTF-8');
71+
$stub = (object) array('cut' => $cut, 'str' => $stub);
72+
}
73+
break;
74+
75+
case 'integer':
76+
break;
77+
78+
case 'array':
79+
if ($v) {
80+
$stub = (object) array('count' => $zval['array_count']);
81+
$arrayRefs[$len] = $stub;
82+
$a = $v;
83+
}
84+
break;
85+
86+
case 'object':
87+
if (empty($softRefs[$h = $zval['object_hash']])) {
88+
$stub = $softRefs[$h] = (object) array('class' => $zval['object_class']);
89+
if (0 > $maxItems || $pos < $maxItems) {
90+
$a = $this->castObject($stub->class, $v, 0 < $i, $cut);
91+
if ($cut) {
92+
$stub->cut = $cut;
93+
}
94+
} else {
95+
$stub->cut = -1;
96+
}
97+
} else {
98+
$stub = $softRefs[$h];
99+
$stub->ref = ++$refs;
100+
}
101+
break;
102+
103+
case 'resource':
104+
if (empty($softRefs[$h = $zval['resource_id']])) {
105+
$stub = $softRefs[$h] = (object) array('res' => $zval['resource_type']);
106+
if (0 > $maxItems || $pos < $maxItems) {
107+
$a = $this->castResource($stub->res, $v, 0 < $i);
108+
} else {
109+
$stub->cut = -1;
110+
}
111+
} else {
112+
$stub = $softRefs[$h];
113+
$stub->ref = ++$refs;
114+
}
115+
break;
116+
}
117+
118+
if (isset($stub)) {
119+
if ($zval['zval_isref']) {
120+
if (isset($stub->count)) {
121+
$queue[$i][$k] = $hardRefs[$zval['zval_hash']] = $stub;
122+
} else {
123+
$queue[$i][$k] = $hardRefs[$zval['zval_hash']] = (object) array('val' => $stub);
124+
}
125+
} else {
126+
$queue[$i][$k] = $stub;
127+
}
128+
129+
if ($a) {
130+
if ($i && 0 <= $maxItems) {
131+
$k = count($a);
132+
if ($p F438 os < $maxItems) {
133+
if ($maxItems < $pos += $k) {
134+
$a = array_slice($a, 0, $maxItems - $pos);
135+
if (empty($stub->cut)) {
136+
$stub->cut = $pos - $maxItems;
137+
} elseif ($stub->cut > 0) {
138+
$stub->cut += $pos - $maxItems;
139+
}
140+
}
141+
} else {
142+
if (empty($stub->cut)) {
143+
$stub->cut = $k;
144+
} elseif ($stub->cut > 0) {
145+
$stub->cut += $k;
146+
}
147+
$stub = $a = null;
148+
unset($arrayRefs[$len]);
149+
continue;
150+
}
151+
}
152+
$queue[$len] = $a;
153+
$stub->pos = $len++;
154+
}
155+
$stub = $a = null;
156+
} elseif ($zval['zval_isref']) {
157+
$queue[$i][$k] = $hardRefs[$zval['zval_hash']] = (object) array('val' => $v);
158+
}
159+
}
160+
161+
if (isset($arrayRefs[$i])) {
162+
if ($indexed) {
163+
$arrayRefs[$i]->indexed = 1;
164+
}
165+
unset($arrayRefs[$i]);
166+
}
167+
}
168+
169+
return $queue;
170+
}
171+
}

0 commit comments

Comments
 (0)
0