Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 5b7ae28

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

File tree

Expand file treeCollapse file tree

1 file changed

+171
-0
lines changed
Filter options
Expand file treeCollapse file tree

1 file changed

+171
-0
lines changed
+171Lines 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 ($pos < $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)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.