@@ -189,9 +189,9 @@ ZEND_API zend_object* ZEND_FASTCALL zend_objects_new(zend_class_entry *ce)
189
189
return object ;
190
190
}
191
191
192
- ZEND_API void ZEND_FASTCALL zend_objects_clone_members_with (zend_object * new_object , zend_object * old_object , const zend_class_entry * scope , const HashTable * properties )
192
+ ZEND_API void ZEND_FASTCALL zend_objects_clone_members (zend_object * new_object , zend_object * old_object )
193
193
{
194
- bool might_update_properties = old_object -> ce -> clone != NULL || zend_hash_num_elements ( properties ) > 0 ;
194
+ bool has_clone_method = old_object -> ce -> clone != NULL ;
195
195
196
196
if (old_object -> ce -> default_properties_count ) {
197
197
zval * src = old_object -> properties_table ;
@@ -202,7 +202,7 @@ ZEND_API void ZEND_FASTCALL zend_objects_clone_members_with(zend_object *new_obj
202
202
i_zval_ptr_dtor (dst );
203
203
ZVAL_COPY_VALUE_PROP (dst , src );
204
204
zval_add_ref (dst );
205
- if (might_update_properties ) {
205
+ if (has_clone_method ) {
206
206
/* Unconditionally add the IS_PROP_REINITABLE flag to avoid a potential cache miss of property_info */
207
207
Z_PROP_FLAG_P (dst ) |= IS_PROP_REINITABLE ;
208
208
}
@@ -217,7 +217,7 @@ ZEND_API void ZEND_FASTCALL zend_objects_clone_members_with(zend_object *new_obj
217
217
src ++ ;
218
218
dst ++ ;
219
219
} while (src != end );
220
- } else if (old_object -> properties && !might_update_properties ) {
220
+ } else if (old_object -> properties && !has_clone_method ) {
221
221
/* fast copy */
222
222
if (EXPECTED (old_object -> handlers == & std_object_handlers )) {
223
223
if (EXPECTED (!(GC_FLAGS (old_object -> properties ) & IS_ARRAY_IMMUTABLE ))) {
@@ -251,7 +251,7 @@ ZEND_API void ZEND_FASTCALL zend_objects_clone_members_with(zend_object *new_obj
251
251
ZVAL_COPY_VALUE (& new_prop , prop );
252
252
zval_add_ref (& new_prop );
253
253
}
254
- if (might_update_properties ) {
254
+ if (has_clone_method ) {
255
255
/* Unconditionally add the IS_PROP_REINITABLE flag to avoid a potential cache miss of property_info */
256
256
Z_PROP_FLAG_P (& new_prop ) |= IS_PROP_REINITABLE ;
257
257
}
@@ -263,45 +263,9 @@ ZEND_API void ZEND_FASTCALL zend_objects_clone_members_with(zend_object *new_obj
263
263
} ZEND_HASH_FOREACH_END ();
264
264
}
265
265
266
- if (might_update_properties ) {
266
+ if (has_clone_method ) {
267
267
GC_ADDREF (new_object );
268
- if (old_object -> ce -> clone ) {
269
- zend_call_known_instance_method_with_0_params (new_object -> ce -> clone , new_object , NULL );
270
- }
271
-
272
- if (EXPECTED (!EG (exception )) && zend_hash_num_elements (properties ) > 0 ) {
273
- /* Unlock readonly properties once more. */
274
- if (ZEND_CLASS_HAS_READONLY_PROPS (new_object -> ce ) && old_object -> ce -> clone ) {
275
- for (uint32_t i = 0 ; i < new_object -> ce -> default_properties_count ; i ++ ) {
276
- zval * prop = OBJ_PROP_NUM (new_object , i );
277
- Z_PROP_FLAG_P (prop ) |= IS_PROP_REINITABLE ;
278
- }
279
- }
280
-
281
- const zend_class_entry * old_scope = EG (fake_scope );
282
-
283
- EG (fake_scope ) = scope ;
284
-
285
- zend_ulong num_key ;
286
- zend_string * key ;
287
- zval * val ;
288
- ZEND_HASH_FOREACH_KEY_VAL (properties , num_key , key , val ) {
289
- if (UNEXPECTED (key == NULL )) {
290
- key = zend_long_to_str (num_key );
291
- new_object -> handlers -> write_property (new_object , key , val , NULL );
292
- zend_string_release_ex (key , false);
293
- } else {
294
- new_object -> handlers -> write_property (new_object , key , val , NULL );
295
- }
296
-
297
- if (UNEXPECTED (EG (exception ))) {
298
- break ;
299
- }
300
- } ZEND_HASH_FOREACH_END ();
301
-
302
- EG (fake_scope ) = old_scope ;
303
- }
304
-
268
+ zend_call_known_instance_method_with_0_params (new_object -> ce -> clone , new_object , NULL );
305
269
306
270
if (ZEND_CLASS_HAS_READONLY_PROPS (new_object -> ce )) {
307
271
for (uint32_t i = 0 ; i < new_object -> ce -> default_properties_count ; i ++ ) {
@@ -315,34 +279,58 @@ ZEND_API void ZEND_FASTCALL zend_objects_clone_members_with(zend_object *new_obj
315
279
}
316
280
}
317
281
318
- ZEND_API void ZEND_FASTCALL zend_objects_clone_members (zend_object * new_object , zend_object * old_object )
319
- {
320
- ZEND_ASSERT (old_object -> ce == new_object -> ce );
321
-
322
- zend_objects_clone_members_with (new_object , old_object , NULL , & zend_empty_array );
323
- }
324
-
325
282
ZEND_API zend_object * zend_objects_clone_obj_with (zend_object * old_object , const zend_class_entry * scope , const HashTable * properties )
326
283
{
327
284
zend_object * new_object ;
328
285
329
- /* Compatibility with code that only overrides clone_obj. */
330
- if (UNEXPECTED (old_object -> handlers -> clone_obj != zend_objects_clone_obj )) {
331
- if (!old_object -> handlers -> clone_obj ) {
332
- zend_throw_error (NULL , "Trying to clone an uncloneable object of class %s" , ZSTR_VAL (old_object -> ce -> name ));
333
- return NULL ;
334
- }
286
+ new_object = old_object -> handlers -> clone_obj (old_object );
287
+
288
+ if (EXPECTED (!EG (exception )) && zend_hash_num_elements (properties ) > 0 ) {
289
+ GC_ADDREF (new_object );
335
290
336
- if (zend_hash_num_elements (properties ) > 0 ) {
337
- zend_throw_error (NULL , "Cloning objects of class %s with updated properties is not supported" , ZSTR_VAL (old_object -> ce -> name ));
338
- return NULL ;
291
+ /* Unlock readonly properties once more. */
292
+ if (ZEND_CLASS_HAS_READONLY_PROPS (new_object -> ce )) {
293
+ for (uint32_t i = 0 ; i < new_object -> ce -> default_properties_count ; i ++ ) {
294
+ zval * prop = OBJ_PROP_NUM (new_object , i );
295
+ Z_PROP_FLAG_P (prop ) |= IS_PROP_REINITABLE ;
296
+ }
339
297
}
340
298
341
- return old_object -> handlers -> clone_obj (old_object );
299
+ const zend_class_entry * old_scope = EG (fake_scope );
300
+
301
+ EG (fake_scope ) = scope ;
302
+
303
+ zend_ulong num_key ;
304
+ zend_string * key ;
305
+ zval * val ;
306
+ ZEND_HASH_FOREACH_KEY_VAL (properties , num_key , key , val ) {
307
+ if (UNEXPECTED (key == NULL )) {
308
+ key = zend_long_to_str (num_key );
309
+ new_object -> handlers -> write_property (new_object , key , val , NULL );
310
+ zend_string_release_ex (key , false);
311
+ } else {
312
+ new_object -> handlers -> write_property (new_object , key , val , NULL );
313
+ }
314
+
315
+ if (UNEXPECTED (EG (exception ))) {
316
+ break ;
317
+ }
318
+ } ZEND_HASH_FOREACH_END ();
319
+
320
+ EG (fake_scope ) = old_scope ;
321
+
322
+ OBJ_RELEASE (new_object );
342
323
}
343
324
325
+ return new_object ;
326
+ }
327
+
328
+ ZEND_API zend_object * zend_objects_clone_obj (zend_object * old_object )
329
+ {
330
+ zend_object * new_object ;
331
+
344
332
if (UNEXPECTED (zend_object_is_lazy (old_object ))) {
345
- return zend_lazy_object_clone (old_object , scope , properties );
333
+ return zend_lazy_object_clone (old_object );
346
334
}
347
335
348
336
/* assume that create isn't overwritten, so when clone depends on the
@@ -359,12 +347,7 @@ ZEND_API zend_object *zend_objects_clone_obj_with(zend_object *old_object, const
359
347
} while (p != end );
360
348
}
361
349
362
- zend_objects_clone_members_with (new_object , old_object , scope , properties );
350
+ zend_objects_clone_members (new_object , old_object );
363
351
364
352
return new_object ;
365
353
}
366
-
367
- ZEND_API zend_object * zend_objects_clone_obj (zend_object * old_object )
368
- {
369
- return zend_objects_clone_obj_with (old_object , NULL , & zend_empty_array );
370
- }
0 commit comments