14
14
/**
15
15
* @author Nicolas Grekas <[email protected] >
16
16
*/
17
- class PhpCloner extends AbstractCloner
17
+ class VarCloner extends AbstractCloner
18
18
{
19
19
/**
20
20
* {@inheritdoc}
21
21
*/
22
22
protected function doClone ($ var )
23
23
{
24
+ $ useExt = extension_loaded ('symfony_debug ' );
24
25
$ i = 0 ; // Current iteration position in $queue
25
26
$ len = 1 ; // Length of $queue
26
27
$ pos = 0 ; // Number of cloned items past the first level
27
28
$ refs = 0 ; // Number of hard+soft references in $var
28
29
$ queue = array (array ($ var )); // This breadth-first queue is the return value
29
30
$ arrayRefs = array (); // Map of queue indexes to stub array objects
30
- $ hardRefs = array (); // By-ref map of stub objects' hashes to original hard `&` references
31
+ $ hardRefs = array (); // Map of original zval hashes to stub objects
31
32
$ softRefs = array (); // Map of original object hashes to their stub object couterpart
32
33
$ values = array (); // Map of stub objects' hashes to original values
33
34
$ maxItems = $ this ->maxItems ;
34
35
$ maxString = $ this ->maxString ;
35
36
$ cookie = (object ) array (); // Unique object used to detect hard references
36
- $ isRef = false ;
37
37
$ a = null ; // Array cast for nested structures
38
38
$ stub = null ; // Stub capturing the main properties of an original item value,
39
39
// or null if the original value is used directly
40
+ $ zval = array ( // Main properties of the current value
41
+ 'type ' => null ,
42
+ 'zval_isref ' => null ,
43
+ 'array_count ' => null ,
44
+ 'object_class ' => null ,
45
+ 'object_hash ' => null ,
46
+ 'resource_type ' => null ,
47
+ );
40
48
41
49
for ($ i = 0 ; $ i < $ len ; ++$ i ) {
42
50
$ indexed = true ; // Whether the currently iterated array is numerically indexed or not
@@ -48,20 +56,33 @@ protected function doClone($var)
48
56
if ($ indexed && $ k !== ++$ j ) {
49
57
$ indexed = false ;
50
58
}
51
- $ step [$ k ] = $ cookie ;
52
- if ($ queue [$ i ][$ k ] === $ cookie ) {
53
- $ queue [$ i ][$ k ] =& $ stub ; // Break hard references to make $queue completely
54
- unset($ stub ); // independent from the original structure
55
- if ($ v instanceof Stub && isset ($ hardRefs [spl_object_hash ($ v )])) {
56
- $ v ->ref = ++$ refs ;
57
- $ step [$ k ] = $ queue [$ i ][$ k ] = $ v ;
58
- continue ;
59
+ if ($ useExt ) {
60
+ $ zval = symfony_zval_info ($ k , $ step );
61
+ if ($ zval ['zval_isref ' ]) {
62
+ $ queue [$ i ][$ k ] =& $ stub ; // Break hard references to make $queue completely
63
+ unset($ stub ); // independent from the original structure
64
+ if (isset ($ hardRefs [$ h = $ zval ['zval_hash ' ]])) {
65
+ $ hardRefs [$ h ]->ref = ++$ refs ;
66
+ $ queue [$ i ][$ k ] = $ hardRefs [$ h ];
67
+ continue ;
68
+ }
69
+ }
70
+ } else {
71
+ $ step [$ k ] = $ cookie ;
72
+ if ($ zval ['zval_isref ' ] = $ queue [$ i ][$ k ] === $ cookie ) {
73
+ $ queue [$ i ][$ k ] =& $ stub ; // Break hard references to make $queue completely
74
+ unset($ stub ); // independent from the original structure
75
+ if ($ v instanceof Stub && isset ($ hardRefs [spl_object_hash ($ v )])) {
76
+ $ v ->ref = ++$ refs ;
77
+ $ step [$ k ] = $ queue [$ i ][$ k ] = $ v ;
78
+ continue ;
79
+ }
59
80
}
60
- $ isRef = true ;
81
+ $ zval [ ' type ' ] = gettype ( $ v ) ;
61
82
}
62
83
// Create $stub when the original value $v can not be used directly
63
84
// If $v is a nested structure, put that structure in array $a
64
- switch (gettype ( $ v ) ) {
85
+ switch ($ zval [ ' type ' ] ) {
65
86
case 'string ' :
66
87
if (isset ($ v [0 ]) && !preg_match ('//u ' , $ v )) {
67
88
$ stub = new Stub ();
@@ -74,7 +95,7 @@ protected function doClone($var)
74
95
$ cut = $ v ;
75
96
}
76
97
$ stub ->value = Data::utf8Encode ($ cut );
77
- } elseif (0 <= $ maxString && isset ($ v [1 + ($ maxString>> 2 )]) && 0 < $ cut = iconv_strlen ($ v , 'UTF-8 ' ) - $ maxString ) {
98
+ } elseif (0 <= $ maxString && isset ($ v [1 + ($ maxString >> 2 )]) && 0 < $ cut = iconv_strlen ($ v , 'UTF-8 ' ) - $ maxString ) {
78
99
$ stub = new Stub ();
79
100
$ stub ->type = Stub::TYPE_STRING ;
80
101
$ stub ->class = Stub::STRING_UTF8 ;
@@ -91,16 +112,16 @@ protected function doClone($var)
91
112
$ stub = $ arrayRefs [$ len ] = new Stub ();
92
113
$ stub ->type = Stub::TYPE_ARRAY ;
93
114
$ stub ->class = Stub::ARRAY_ASSOC ;
94
- $ stub ->value = count ($ v );
115
+ $ stub ->value = $ v ? $ zval [ ' array_count ' ] ?: count ($ v ) : 0 ;
95
116
$ a = $ v ;
96
117
}
97
118
break ;
98
119
99
120
case 'object ' :
100
- if (empty ($ softRefs [$ h = spl_object_hash ($ v )])) {
121
+ if (empty ($ softRefs [$ h = $ zval [ ' object_hash ' ] ?: spl_object_hash ($ v )])) {
101
122
$ stub = new Stub ();
102
123
$ stub ->type = Stub::TYPE_OBJECT ;
103
- $ stub ->class = get_class ($ v );
124
+ $ stub ->class = $ zval [ ' object_class ' ] ?: get_class ($ v );
104
125
$ stub ->value = $ v ;
105
126
$ a = $ this ->castObject ($ stub , 0 < $ i );
106
127
if ($ v !== $ stub ->value ) {
@@ -129,7 +150,7 @@ protected function doClone($var)
129
150
if (empty ($ softRefs [$ h = (int ) $ v ])) {
130
151
$ stub = new Stub ();
131
152
$ stub ->type = Stub::TYPE_RESOURCE ;
132
- $ stub ->class = get_resource_type ($ v );
153
+ $ stub ->class = $ zval [ ' resource_type ' ] ?: get_resource_type ($ v );
133
154
$ stub ->value = $ v ;
134
155
$ a = $ this ->castResource ($ stub , 0 < $ i );
135
156
if ($ v !== $ stub ->value ) {
@@ -155,17 +176,25 @@ protected function doClone($var)
155
176
}
156
177
157
178
if (isset ($ stub )) {
158
- if ($ isRef ) {
159
- if (Stub::TYPE_ARRAY === $ stub ->type ) {
160
- $ step [$ k ] = $ stub ;
179
+ if ($ zval ['zval_isref ' ]) {
180
+ if ($ useExt ) {
181
+ if (Stub::TYPE_ARRAY === $ stub ->type ) {
182
+ $ queue [$ i ][$ k ] = $ hardRefs [$ zval ['zval_hash ' ]] = $ stub ;
183
+ } else {
184
+ $ queue [$ i ][$ k ] = $ hardRefs [$ zval ['zval_hash ' ]] = $ v = new Stub ();
185
+ $ v ->value = $ stub ;
186
+ }
161
187
} else {
162
- $ step [$ k ] = new Stub ();
163
- $ step [$ k ]->value = $ stub ;
188
+ if (Stub::TYPE_ARRAY === $ stub ->type ) {
189
+ $ step [$ k ] = $ stub ;
190
+ } else {
191
+ $ step [$ k ] = new Stub ();
192
+ $ step [$ k ]->value = $ stub ;
193
+ }
194
+ $ h = spl_object_hash ($ step [$ k ]);
195
+ $ queue [$ i ][$ k ] = $ hardRefs [$ h ] =& $ step [$ k ];
196
+ $ values [$ h ] = $ v ;
164
197
}
165
- $ h = spl_object_hash ($ step [$ k ]);
166
- $ queue [$ i ][$ k ] = $ hardRefs [$ h ] =& $ step [$ k ];
167
- $ values [$ h ] = $ v ;
168
- $ isRef = false ;
169
198
} else {
170
199
$ queue [$ i ][$ k ] = $ stub ;
171
200
}
@@ -193,13 +222,17 @@ protected function doClone($var)
193
222
$ stub ->position = $ len ++;
194
223
}
195
224
$ stub = $ a = null ;
196
- } elseif ($ isRef ) {
197
- $ step [$ k ] = $ queue [$ i ][$ k ] = new Stub ();
198
- $ step [$ k ]->value = $ v ;
199
- $ h = spl_object_hash ($ step [$ k ]);
200
- $ hardRefs [$ h ] =& $ step [$ k ];
201
- $ values [$ h ] = $ v ;
202
- $ isRef = false ;
225
+ } elseif ($ zval ['zval_isref ' ]) {
226
+ if ($ useExt ) {
227
+ $ queue [$ i ][$ k ] = $ hardRefs [$ zval ['zval_hash ' ]] = new Stub ();
228
+ $ queue [$ i ][$ k ]->value = $ v ;
229
+ } else {
230
+ $ step [$ k ] = $ queue [$ i ][$ k ] = new Stub ();
231
+ $ step [$ k ]->value = $ v ;
232
+ $ h = spl_object_hash ($ step [$ k ]);
233
+ $ hardRefs [$ h ] =& $ step [$ k ];
234
+ $ values [$ h ] = $ v ;
235
+ }
203
236
}
204
237
}
205
238
0 commit comments