@@ -48,10 +48,11 @@ public static function prepare($values, $objectsPool, &$refsPool, &$objectsCount
48
48
$ refs [$ k ] = $ value = $ values [$ k ];
49
49
if ($ value instanceof Reference && 0 > $ value ->id ) {
50
50
$ valuesAreStatic = false ;
51
+ ++$ value ->count ;
51
52
continue ;
52
53
}
53
54
$ refsPool [] = array (&$ refs [$ k ], $ value , &$ value );
54
- $ refs [$ k ] = $ values [$ k ] = new Reference (-\count ($ refsPool ));
55
+ $ refs [$ k ] = $ values [$ k ] = new Reference (-\count ($ refsPool ), $ value );
55
56
}
56
57
57
58
if (\is_array ($ value )) {
@@ -80,12 +81,13 @@ public static function prepare($values, $objectsPool, &$refsPool, &$objectsCount
80
81
Registry::getClassReflector ($ class );
81
82
serialize (Registry::$ prototypes [$ class ]);
82
83
}
84
+ $ reflector = Registry:
F438
:$ reflectors [$ class ];
83
85
$ proto = Registry::$ prototypes [$ class ];
84
86
85
87
if ($ value instanceof \ArrayIterator || $ value instanceof \ArrayObject) {
86
88
// ArrayIterator and ArrayObject need special care because their "flags"
87
89
// option changes the behavior of the (array) casting operator.
88
- $ proto = Registry::$ cloneable [$ class ] ? clone Registry::$ prototypes [$ class ] : Registry:: $ reflectors [ $ class ] ->newInstanceWithoutConstructor ();
90
+ $ proto = Registry::$ cloneable [$ class ] ? clone Registry::$ prototypes [$ class ] : $ reflector ->newInstanceWithoutConstructor ();
89
91
$ properties = self ::getArrayObjectProperties ($ value , $ arrayValue , $ proto );
90
92
} elseif ($ value instanceof \SplObjectStorage) {
91
93
// By implementing Serializable, SplObjectStorage breaks internal references,
@@ -116,20 +118,29 @@ public static function prepare($values, $objectsPool, &$refsPool, &$objectsCount
116
118
foreach ($ arrayValue as $ name => $ v ) {
117
119
$ n = (string ) $ name ;
118
120
if ('' === $ n || "\0" !== $ n [0 ]) {
119
- $ c = $ class ;
121
+ $ c = '* ' ;
122
+ $ properties [$ c ][$ n ] = $ v ;
123
+ unset($ sleep [$ n ]);
120
124
} elseif ('* ' === $ n [1 ]) {
121
- $ c = $ class ;
122
125
$ n = substr ($ n , 3 );
126
+ $ c = $ reflector ->getProperty ($ n )->class ;
127
+ if ('Error ' === $ c ) {
128
+ $ c = 'TypeError ' ;
129
+ } elseif ('Exception ' === $ c ) {
130
+ $ c = 'ErrorException ' ;
131
+ }
132
+ $ properties [$ c ][$ n ] = $ v ;
133
+ unset($ sleep [$ n ]);
123
134
} else {
124
135
$ i = strpos ($ n , "\0" , 2 );
125
136
$ c = substr ($ n , 1 , $ i - 1 );
126
137
$ n = substr ($ n , 1 + $ i );
127
- }
128
- if ( null === $ sleep ) {
129
- $ properties [ $ c ][ $ n ] = $ v ;
130
- } elseif ( isset ( $ sleep [ $ n ]) && $ c === $ class ) {
131
- $ properties [ $ c ][ $ n ] = $ v ;
132
- unset( $ sleep [ $ n ]);
138
+ if ( null === $ sleep ) {
139
+ $ properties [ $ c ][ $ n ] = $ v ;
140
+ } elseif ( isset ( $ sleep [ $ n ]) && $ c === $ class ) {
141
+ $ properties [ $ c ][ $ n ] = $ v ;
142
+ unset( $ sleep [ $ n ]) ;
143
+ }
133
144
}
134
145
if (\array_key_exists ($ name , $ proto ) && $ proto [$ name ] === $ v ) {
135
146
unset($ properties [$ c ][$ n ]);
@@ -173,11 +184,14 @@ public static function export($value, $indent = '')
173
184
174
185
if ($ value instanceof Reference) {
175
186
if (0 <= $ value ->id ) {
176
- return '\\' .Registry::class.'::$objects[ ' .$ value ->id .'] ' ;
187
+ return '$o[ ' .$ value ->id .'] ' ;
188
+ }
189
+ if (!$ value ->count ) {
190
+ return self ::export ($ value ->value , $ indent );
177
191
}
178
192
$ value = -$ value ->id ;
179
193
180
- return '& \\' .Registry::class. ' ::$references [ ' .$ value .'] ' ;
194
+ return '&$r [ ' .$ value .'] ' ;
181
195
}
182
196
$ subIndent = $ indent .' ' ;
183
197
@@ -213,9 +227,11 @@ public static function export($value, $indent = '')
213
227
$ code = '' ;
214
228
foreach ($ value as $ k => $ v ) {
215
229
$ code .= $ subIndent ;
216
- if ($ k !== ++ $ j ) {
230
+ if (! \is_int ( $ k ) || 1 !== $ k - $ j ) {
217
231
$ code .= self ::export ($ k , $ subIndent ).' => ' ;
218
- $ j = INF ;
232
+ }
233
+ if (\is_int ($ k )) {
234
+ $ j = $ k ;
219
235
}
220
236
$ code .= self ::export ($ v , $ subIndent ).", \n" ;
221
237
}
@@ -224,82 +240,110 @@ public static function export($value, $indent = '')
224
240
}
225
241
226
242
if ($ value instanceof Values) {
227
- $ code = '' ;
243
+ $ code = $ subIndent . "\$ r = [], \n" ;
228
244
foreach ($ value ->values as $ k => $ v ) {
229
- $ code .= $ subIndent .'\\' .Registry::class. ' ::$references [ ' .$ k .'] = ' .self ::export ($ v , $ subIndent ).", \n" ;
245
+ $ code .= $ subIndent .'$r [ ' .$ k .'] = ' .self ::export ($ v , $ subIndent ).", \n" ;
230
246
}
231
247
232
248
return "[ \n" .$ code .$ indent .'] ' ;
233
249
}
234
250
235
251
if ($ value instanceof Registry) {
236
- $ code = '' ;
237
- $ reflectors = array ();
238
- $ serializables = array ();
252
+ return self ::exportRegistry ($ value , $ indent , $ subIndent );
253
+ }
239
254
240
- foreach ($ value as $ k => $ class ) {
241
- if (': ' === ($ class [1 ] ?? null )) {
242
- $ serializables [$ k ] = $ class ;
243
- continue ;
244
- }
245
- $ c = '\\' .$ class .'::class ' ;
246
- $ reflectors [$ class ] = '\\' .Registry::class.'::$reflectors[ ' .$ c .'] ?? \\' .Registry::class.'::getClassReflector( ' .$ c .', '
247
- .self ::export (Registry::$ instantiableWithoutConstructor [$ class ]).', '
248
- .self ::export (Registry::$ cloneable [$ class ])
249
- .') ' ;
255
+ if ($ value instanceof Hydrator) {
256
+ return self ::exportHydrator ($ value , $ indent , $ subIndent );
257
+ }
258
+
259
+ throw new \UnexpectedValueException (sprintf ('Cannot export value of type "%s". ' , \is_object ($ value ) ? \get_class ($ value ) : \gettype ($ value )));
260
+ }
261
+
262
+ private static function exportRegistry (Registry $ value , string $ indent , string $ subIndent ): string
263
+ {
264
+ $ code = '' ;
265
+ $ reflectors = array ();
266
+ $ serializables = array ();
267
+ $ seen = array ();
268
+ $ prototypesAccess = 0 ;
269
+ $ factoriesAccess = 0 ;
270
+ $ r = '\\' .Registry::class;
271
+ $ j = -1 ;
272
+
273
+ foreach ($ value as $ k => $ class ) {
274
+ if (': ' === ($ class [1 ] ?? null )) {
275
+ $ serializables [$ k ] = $ class ;
276
+ continue ;
277
+ }
278
+ $ code .= $ subIndent .(1 !== $ k - $ j ? $ k .' => ' : '' );
279
+ $ j = $ k ;
280
+ $ eol = ", \n" ;
281
+ $ c = '[ \\' .$ class .'::class] ' ;
250
282
283
+ if ($ seen [$ class ] ?? false ) {
251
284
if (Registry::$ cloneable [$ class ]) {
252
- $ code .= $ subIndent .'clone \\' .Registry::class.'::$prototypes[ ' .$ c ."], \n" ;
253
- } elseif (Registry::$ instantiableWithoutConstructor [$ class ]) {
254
- $ code .= $ subIndent .'\\' .Registry::class.'::$reflectors[ ' .$ c ."]->newInstanceWithoutConstructor(), \n" ;
285
+ ++$ prototypesAccess ;
286
+ $ code .= 'clone $p ' .$ c ;
255
287
} else {
256
- $ code .= $ subIndent .'\\' .Registry::class.'::$reflectors[ ' .$ c ."]->newInstance(), \n" ;
288
+ ++$ factoriesAccess ;
289
+ $ code .= '$f ' .$ c .'() ' ;
257
290
}
258
- }
259
-
260
- if ($ reflectors ) {
261
- $ code = "[ \n" .$ subIndent .implode (", \n" .$ subIndent , $ reflectors ).", \n" .$ indent ."], [ \n" .$ code .$ indent .'], ' ;
262
- $ code .= !$ serializables ? "[ \n" .$ indent .'] ' : self ::export ($ serializables , $ indent );
263
291
} else {
264
- $ code = '[], [] ' ;
265
- $ code .= ', ' .self ::export ($ serializables , $ indent );
292
+ $ seen [$ class ] = true ;
293
+ if (Registry::$ cloneable [$ class ]) {
294
+ $ code .= 'clone ( ' .($ prototypesAccess ++ ? '$p ' : '($p =& ' .$ r .'::$prototypes) ' ).$ c .' ?? ' .$ r .'::p ' ;
295
+ } else {
296
+ $ code .= '( ' .($ factoriesAccess ++ ? '$f ' : '($f =& ' .$ r .'::$factories) ' ).$ c .' ?? ' .$ r .'::f ' ;
297
+ $ eol = '() ' .$ eol ;
298
+ }
299
+ $ code .= '( ' .substr ($ c , 1 , -1 ).', ' .self ::export (Registry::$ instantiableWithoutConstructor [$ class ]).')) ' ;
266
300
}
301
+ $ code .= $ eol ;
302
+ }
267
303
268
- return '\\' .Registry::class.'::push( ' .$ code .') ' ;
304
+ if (1 === $ prototypesAccess ) {
305
+ $ code = str_replace ('($p =& ' .$ r .'::$prototypes) ' , $ r .'::$prototypes ' , $ code );
306
+ }
307
+ if (1 === $ factoriesAccess ) {
308
+ $ code = str_replace ('($f =& ' .$ r .'::$factories) ' , $ r .'::$factories ' , $ code );
309
+ }
310
+ if ('' !== $ code ) {
311
+ $ code = "\n" .$ code .$ indent ;
269
312
}
270
313
271
- if ($ value instanceof Configurator ) {
272
- $ code = ' ' ;
273
- foreach ( $ value -> properties as $ class => $ properties ) {
274
- $ code .= $ subIndent . ' \\ ' .$ class . ' ::class => ' . self :: export ( $ properties , $ subIndent . ' ' ). " , \n" ;
275
- }
314
+ if ($ serializables ) {
315
+ $ code = $ r . ' ::unserialize([ ' . $ code . ' ], ' . self :: export ( $ serializables , $ indent ). ' ) ' ;
316
+ } else {
317
+ $ code = ' [ ' .$ code . ' ] ' ;
318
+ }
276
319
277
- $ code = array (
278
- self ::export ($ value ->registry , $ subIndent ),
279
- self ::export ($ value ->values , $ subIndent ),
280
- '' !== $ code ? "[ \n" .$ code .$ subIndent .'] ' : '[] ' ,
281
- self ::export ($ value ->value , $ subIndent ),
282
- self ::export ($ value ->wakeups , $ subIndent ),
283
- );
320
+ return '$o = ' .$ code ;
321
+ }
284
322
285
- return '\\' .\get_class ($ value )."::pop( \n" .$ subIndent .implode (", \n" .$ subIndent , $ code )."\n" .$ indent .') ' ;
323
+ private static function exportHydrator (Hydrator $ value , string $ indent , string $ subIndent ): string
324
+ {
325
+ $ code = '' ;
326
+ foreach ($ value ->properties as $ class => $ properties ) {
327
+ $ c = '* ' !== $ class ? '\\' .$ class .'::class ' : "'*' " ;
328
+ $ code .= $ subIndent .' ' .$ c .' => ' .self ::export ($ properties , $ subIndent .' ' ).", \n" ;
286
329
}
287
330
288
- throw new \UnexpectedValueException (sprintf ('Cannot export value of type "%s". ' , \is_object ($ value ) ? \get_class ($ value ) : \gettype ($ value )));
331
+ $ code = array (
332
+ self ::export ($ value ->registry , $ subIndent ),
333
+ self ::export ($ value ->values , $ subIndent ),
334
+ '' !== $ code ? "[ \n" .$ code .$ subIndent .'] ' : '[] ' ,
335
+ self ::export ($ value ->value , $ subIndent ),
336
+ self ::export ($ value ->wakeups , $ subIndent ),
337
+ );
338
+
339
+ return '\\' .\get_class ($ value )."::hydrate( \n" .$ subIndent .implode (", \n" .$ subIndent , $ code )."\n" .$ indent .') ' ;
289
340
}
290
341
291
342
/**
292
- * Extracts the state of an ArrayIterator or ArrayObject instance.
293
- *
294
- * For performance this method is public and has no type-hints.
295
- *
296
343
* @param \ArrayIterator|\ArrayObject $value
297
- * @param array &$arrayValue
298
- * @param object $proto
299
- *
300
- * @return array
344
+ * @param \ArrayIterator|\ArrayObject $proto
301
345
*/
302
- public static function getArrayObjectProperties ($ value , &$ arrayValue , $ proto )
346
+ private static function getArrayObjectProperties ($ value , array &$ arrayValue , $ proto ): array
303
347
{
304
348
$ reflector = $ value instanceof \ArrayIterator ? 'ArrayIterator ' : 'ArrayObject ' ;
305
349
$ reflector = Registry::$ reflectors [$ reflector ] ?? Registry::getClassReflector ($ reflector );
0 commit comments