@@ -213,9 +213,9 @@ ZEND_API zend_object* ZEND_FASTCALL zend_objects_new(zend_class_entry *ce)
213
213
return object ;
214
214
}
215
215
216
- ZEND_API void ZEND_FASTCALL zend_objects_clone_members (zend_object * new_object , zend_object * old_object )
216
+ ZEND_API void ZEND_FASTCALL zend_objects_clone_members_ex (zend_object * new_object , zend_object * old_object , zend_class_entry * scope , HashTable * properties )
217
217
{
218
- bool has_clone_method = old_object -> ce -> clone != NULL ;
218
+ bool has_clone_method = old_object -> ce -> clone != NULL || properties != NULL ;
219
219
220
220
if (old_object -> ce -> default_properties_count ) {
221
221
zval * src = old_object -> properties_table ;
@@ -289,7 +289,29 @@ ZEND_API void ZEND_FASTCALL zend_objects_clone_members(zend_object *new_object,
289
289
290
290
if (has_clone_method ) {
291
291
GC_ADDREF (new_object );
292
- zend_call_known_instance_method_with_0_params (new_object -> ce -> clone , new_object , NULL );
292
+ if (old_object -> ce -> clone ) {
293
+ zend_call_known_instance_method_with_0_params (new_object -> ce -> clone , new_object , NULL );
294
+ }
295
+
296
+ if (EXPECTED (!EG (exception )) && properties != NULL ) {
297
+ zend_ulong num_key ;
298
+ zend_string * key ;
299
+ zval * val ;
300
+ ZEND_HASH_FOREACH_KEY_VAL (properties , num_key , key , val ) {
301
+ if (UNEXPECTED (key == NULL )) {
302
+ key = zend_long_to_str (num_key );
303
+ zend_update_property_ex (scope , new_object , key , val );
304
+ zend_string_release_ex (key , false);
305
+ } else {
306
+ zend_update_property_ex (scope , new_object , key , val );
307
+ }
308
+
309
+ if (UNEXPECTED (EG (exception ))) {
310
+ break ;
311
+ }
312
+ } ZEND_HASH_FOREACH_END ();
313
+ }
314
+
293
315
294
316
if (ZEND_CLASS_HAS_READONLY_PROPS (new_object -> ce )) {
295
317
for (uint32_t i = 0 ; i < new_object -> ce -> default_properties_count ; i ++ ) {
@@ -303,12 +325,33 @@ ZEND_API void ZEND_FASTCALL zend_objects_clone_members(zend_object *new_object,
303
325
}
304
326
}
305
327
306
- ZEND_API zend_object * zend_objects_clone_obj (zend_object * old_object )
328
+ ZEND_API void ZEND_FASTCALL zend_objects_clone_members (zend_object * new_object , zend_object * old_object )
329
+ {
330
+ ZEND_ASSERT (old_object -> ce == new_object -> ce );
331
+
332
+ zend_objects_clone_members_ex (new_object , old_object , old_object -> ce , NULL );
333
+ }
334
+
335
+ ZEND_API zend_object * zend_objects_clone_obj_with (zend_object * old_object , zend_class_entry * scope , HashTable * properties )
307
336
{
308
337
zend_object * new_object ;
309
338
339
+ /* Compatibility with code that only overrides clone_obj. */
340
+ if (UNEXPECTED (old_object -> handlers -> clone_obj != zend_objects_clone_obj )) {
341
+ if (!old_object -> handlers -> clone_obj ) {
342
+ zend_throw_error (NULL , "Trying to clone an uncloneable object of class %s" , ZSTR_VAL (old_object -> ce -> name ));
343
+ return NULL ;
344
+ }
345
+ if (properties && zend_hash_num_elements (properties ) > 0 ) {
346
+ zend_throw_error (NULL , "Trying to clone an object with updated properties that is not compatible %s" , ZSTR_VAL (old_object -> ce -> name ));
347
+ return NULL ;
348
+ } else {
349
+ return old_object -> handlers -> clone_obj (old_object );
350
+ }
351
+ }
352
+
310
353
if (UNEXPECTED (zend_object_is_lazy (old_object ))) {
311
- return zend_lazy_object_clone (old_object );
354
+ return zend_lazy_object_clone (old_object , scope , properties );
312
355
}
313
356
314
357
/* assume that create isn't overwritten, so when clone depends on the
@@ -325,7 +368,12 @@ ZEND_API zend_object *zend_objects_clone_obj(zend_object *old_object)
325
368
} while (p != end );
326
369
}
327
370
328
- zend_objects_clone_members (new_object , old_object );
371
+ zend_objects_clone_members_ex (new_object , old_object , scope , properties );
329
372
330
373
return new_object ;
331
374
}
375
+
376
+ ZEND_API zend_object * zend_objects_clone_obj (zend_object * old_object )
377
+ {
378
+ return zend_objects_clone_obj_with (old_object , old_object -> ce , NULL );
379
+ }
0 commit comments