17
17
class VarCloner extends AbstractCloner
18
18
{
19
19
private static $ gid ;
20
- private static $ hashMask = 0 ;
21
- private static $ hashOffset = 0 ;
22
20
private static $ arrayCache = array ();
23
21
24
22
/**
@@ -31,10 +29,10 @@ protected function doClone($var)
31
29
$ refsCounter = 0 ; // Hard references counter
32
30
$ queue = array (array ($ var )); // This breadth-first queue is the return value
33
31
$ indexedArrays = array (); // Map of queue indexes that hold numerically indexed arrays
34
- $ hardRefs = array (); // Map of original zval hashes to stub objects
32
+ $ hardRefs = array (); // Map of original zval ids to stub objects
35
33
$ objRefs = array (); // Map of original object handles to their stub object couterpart
36
34
$ resRefs = array (); // Map of original resource handles to their stub object couterpart
37
- $ values = array (); // Map of stub objects' hashes to original values
35
+ $ values = array (); // Map of stub objects' ids to original values
38
36
$ maxItems = $ this ->maxItems ;
39
37
$ maxString = $ this ->maxString ;
40
38
$ minDepth = $ this ->minDepth ;
@@ -46,13 +44,9 @@ protected function doClone($var)
46
44
$ stub = null ; // Stub capturing the main properties of an original item value
47
45
// or null if the original value is used directly
48
46
49
- if (!self ::$ hashMask ) {
50
- self ::$ gid = uniqid (mt_rand (), true ); // Unique string used to detect the special $GLOBALS variable
51
- self ::initHashMask ();
47
+ if (!$ gid = self ::$ gid ) {
48
+ $ gid = self ::$ gid = uniqid (mt_rand (), true ); // Unique string used to detect the special $GLOBALS variable
52
49
}
53
- $ gid = self ::$ gid ;
54
- $ hashMask = self ::$ hashMask ;
55
- $ hashOffset = self ::$ hashOffset ;
56
50
$ arrayStub = new Stub ();
57
51
$ arrayStub ->type = Stub::TYPE_ARRAY ;
58
52
$ fromObjCast = false ;
@@ -89,7 +83,7 @@ protected function doClone($var)
89
83
if ($ zvalIsRef = $ vals [$ k ] === $ cookie ) {
90
84
$ vals [$ k ] = &$ stub ; // Break hard references to make $queue completely
91
85
unset($ stub ); // independent from the original structure
92
- if ($ v instanceof Stub && isset ($ hardRefs [\spl_object_hash ($ v )])) {
86
+ if ($ v instanceof Stub && isset ($ hardRefs [\spl_object_id ($ v )])) {
93
87
$ vals [$ k ] = $ refs [$ k ] = $ v ;
94
88
if ($ v ->value instanceof Stub && (Stub::TYPE_OBJECT === $ v ->value ->type || Stub::TYPE_RESOURCE === $ v ->value ->type )) {
95
89
++$ v ->value ->refCount ;
@@ -99,7 +93,7 @@ protected function doClone($var)
99
93
}
100
94
$ refs [$ k ] = $ vals [$ k ] = new Stub ();
101
95
$ refs [$ k ]->value = $ v ;
102
- $ h = \spl_object_hash ($ refs [$ k ]);
96
+ $ h = \spl_object_id ($ refs [$ k ]);
103
97
$ hardRefs [$ h ] = &$ refs [$ k ];
104
98
$ values [$ h ] = $ v ;
105
99
$ vals [$ k ]->handle = ++$ refsCounter ;
@@ -172,7 +166,7 @@ protected function doClone($var)
172
166
173
167
case \is_object ($ v ):
174
168
case $ v instanceof \__PHP_Incomplete_Class:
175
- if (empty ($ objRefs [$ h = $ hashMask ^ \hexdec ( \substr ( \spl_object_hash ( $ v ), $ hashOffset , \ PHP_INT_SIZE ) )])) {
169
+ if (empty ($ objRefs [$ h = \spl_object_id ( $ v )])) {
176
170
$ stub = new Stub ();
177
171
$ stub ->type = Stub::TYPE_OBJECT ;
178
172
$ stub ->class = \get_class ($ v );
@@ -183,8 +177,7 @@ protected function doClone($var)
183
177
if (Stub::TYPE_OBJECT !== $ stub ->type || null === $ stub ->value ) {
184
178
break ;
185
179
}
186
- $ h = $ hashMask ^ \hexdec (\substr (\spl_object_hash ($ stub ->value ), $ hashOffset , \PHP_INT_SIZE ));
187
- $ stub ->handle = $ h ;
180
+ $ stub ->handle = $ h = \spl_object_id ($ stub ->value );
188
181
}
189
182
$ stub ->value = null ;
190
183
if (0 <= $ maxItems && $ maxItems <= $ pos && $ minimumDepthReached ) {
@@ -291,27 +284,4 @@ protected function doClone($var)
291
284
292
285
return $ queue ;
293
286
}
294
-
295
- private static function initHashMask ()
296
- {
297
- $ obj = (object ) array ();
298
- self ::$ hashOffset = 16 - PHP_INT_SIZE ;
299
- self ::$ hashMask = -1 ;
300
-
301
- // check if we are nested in an output buffering handler to prevent a fatal error with ob_start() below
302
- $ obFuncs = array ('ob_clean ' , 'ob_end_clean ' , 'ob_flush ' , 'ob_end_flush ' , 'ob_get_contents ' , 'ob_get_flush ' );
303
- foreach (debug_backtrace (DEBUG_BACKTRACE_IGNORE_ARGS ) as $ frame ) {
304
- if (isset ($ frame ['function ' ][0 ]) && !isset ($ frame ['class ' ]) && 'o ' === $ frame ['function ' ][0 ] && in_array ($ frame ['function ' ], $ obFuncs )) {
305
- $ frame ['line ' ] = 0 ;
306
- break ;
307
- }
308
- }
309
- if (!empty ($ frame ['line ' ])) {
310
- ob_start ();
311
- debug_zval_dump ($ obj );
312
- self ::$ hashMask = (int ) substr (ob_get_clean (), 17 );
313
- }
314
-
315
- self ::$ hashMask ^= hexdec (substr (spl_object_hash ($ obj ), self ::$ hashOffset , PHP_INT_SIZE ));
316
- }
317
287
}
0 commit comments