@@ -189,9 +189,9 @@ ZEND_API zend_object* ZEND_FASTCALL zend_objects_new(zend_class_entry *ce)
189189 return object ;
190190}
191191
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 )
193193{
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 ;
195195
196196 if (old_object -> ce -> default_properties_count ) {
197197 zval * src = old_object -> properties_table ;
@@ -202,7 +202,7 @@ ZEND_API void ZEND_FASTCALL zend_objects_clone_members_with(zend_object *new_obj
202202 i_zval_ptr_dtor (dst );
203203 ZVAL_COPY_VALUE_PROP (dst , src );
204204 zval_add_ref (dst );
205- if (might_update_properties ) {
205+ if (has_clone_method ) {
206206 /* Unconditionally add the IS_PROP_REINITABLE flag to avoid a potential cache miss of property_info */
207207 Z_PROP_FLAG_P (dst ) |= IS_PROP_REINITABLE ;
208208 }
@@ -217,7 +217,7 @@ ZEND_API void ZEND_FASTCALL zend_objects_clone_members_with(zend_object *new_obj
217217 src ++ ;
218218 dst ++ ;
219219 } while (src != end );
220- } else if (old_object -> properties && !might_update_properties ) {
220+ } else if (old_object -> properties && !has_clone_method ) {
221221 /* fast copy */
222222 if (EXPECTED (old_object -> handlers == & std_object_handlers )) {
223223 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
251251 ZVAL_COPY_VALUE (& new_prop , prop );
252252 zval_add_ref (& new_prop );
253253 }
254- if (might_update_properties ) {
254+ if (has_clone_method ) {
255255 /* Unconditionally add the IS_PROP_REINITABLE flag to avoid a potential cache miss of property_info */
256256 Z_PROP_FLAG_P (& new_prop ) |= IS_PROP_REINITABLE ;
257257 }
@@ -263,44 +263,8 @@ ZEND_API void ZEND_FASTCALL zend_objects_clone_members_with(zend_object *new_obj
263263 } ZEND_HASH_FOREACH_END ();
264264 }
265265
266- if (might_update_properties ) {
267- if (old_object -> ce -> clone ) {
268- zend_call_known_instance_method_with_0_params (new_object -> ce -> clone , new_object , NULL );
269- }
270-
271- if (EXPECTED (!EG (exception )) && zend_hash_num_elements (properties ) > 0 ) {
272- /* Unlock readonly properties once more. */
273- if (ZEND_CLASS_HAS_READONLY_PROPS (new_object -> ce ) && old_object -> ce -> clone ) {
274- for (uint32_t i = 0 ; i < new_object -> ce -> default_properties_count ; i ++ ) {
275- zval * prop = OBJ_PROP_NUM (new_object , i );
276- Z_PROP_FLAG_P (prop ) |= IS_PROP_REINITABLE ;
277- }
278- }
279-
280- const zend_class_entry * old_scope = EG (fake_scope );
281-
282- EG (fake_scope ) = scope ;
283-
284- zend_ulong num_key ;
285- zend_string * key ;
286- zval * val ;
287- ZEND_HASH_FOREACH_KEY_VAL (properties , num_key , key , val ) {
288- if (UNEXPECTED (key == NULL )) {
289- key = zend_long_to_str (num_key );
290- new_object -> handlers -> write_property (new_object , key , val , NULL );
291- zend_string_release_ex (key , false);
292- } else {
293- new_object -> handlers -> write_property (new_object , key , val , NULL );
294- }
295-
296- if (UNEXPECTED (EG (exception ))) {
297- break ;
298- }
299- } ZEND_HASH_FOREACH_END ();
300-
301- EG (fake_scope ) = old_scope ;
302- }
303-
266+ if (has_clone_method ) {
267+ zend_call_known_instance_method_with_0_params (new_object -> ce -> clone , new_object , NULL );
304268
305269 if (ZEND_CLASS_HAS_READONLY_PROPS (new_object -> ce )) {
306270 for (uint32_t i = 0 ; i < new_object -> ce -> default_properties_count ; i ++ ) {
@@ -312,34 +276,52 @@ ZEND_API void ZEND_FASTCALL zend_objects_clone_members_with(zend_object *new_obj
312276 }
313277}
314278
315- ZEND_API void ZEND_FASTCALL zend_objects_clone_members (zend_object * new_object , zend_object * old_object )
316- {
317- ZEND_ASSERT (old_object -> ce == new_object -> ce );
318-
319- zend_objects_clone_members_with (new_object , old_object , NULL , & zend_empty_array );
320- }
321-
322279ZEND_API zend_object * zend_objects_clone_obj_with (zend_object * old_object , const zend_class_entry * scope , const HashTable * properties )
323280{
324- zend_object * new_object ;
281+ zend_object * new_object = old_object -> handlers -> clone_obj ( old_object ) ;
325282
326- /* Compatibility with code that only overrides clone_obj. */
327- if (UNEXPECTED (old_object -> handlers -> clone_obj != zend_objects_clone_obj )) {
328- if (!old_object -> handlers -> clone_obj ) {
329- zend_throw_error (NULL , "Trying to clone an uncloneable object of class %s" , ZSTR_VAL (old_object -> ce -> name ));
330- return NULL ;
283+ if (EXPECTED (!EG (exception )) && zend_hash_num_elements (properties ) > 0 ) {
284+ /* Unlock readonly properties once more. */
285+ if (ZEND_CLASS_HAS_READONLY_PROPS (new_object -> ce )) {
286+ for (uint32_t i = 0 ; i < new_object -> ce -> default_properties_count ; i ++ ) {
287+ zval * prop = OBJ_PROP_NUM (new_object , i );
288+ Z_PROP_FLAG_P (prop ) |= IS_PROP_REINITABLE ;
289+ }
331290 }
332291
333- if (zend_hash_num_elements (properties ) > 0 ) {
334- zend_throw_error (NULL , "Cloning objects of class %s with updated properties is not supported" , ZSTR_VAL (old_object -> ce -> name ));
335- return NULL ;
336- }
292+ const zend_class_entry * old_scope = EG (fake_scope );
293+
294+ EG (fake_scope ) = scope ;
295+
296+ zend_ulong num_key ;
297+ zend_string * key ;
298+ zval * val ;
299+ ZEND_HASH_FOREACH_KEY_VAL (properties , num_key , key , val ) {
300+ if (UNEXPECTED (key == NULL )) {
301+ key = zend_long_to_str (num_key );
302+ new_object -> handlers -> write_property (new_object , key , val , NULL );
303+ zend_string_release_ex (key , false);
304+ } else {
305+ new_object -> handlers -> write_property (new_object , key , val , NULL );
306+ }
307+
308+ if (UNEXPECTED (EG (exception ))) {
309+ break ;
310+ }
311+ } ZEND_HASH_FOREACH_END ();
337312
338- return old_object -> handlers -> clone_obj ( old_object ) ;
313+ EG ( fake_scope ) = old_scope ;
339314 }
340315
316+ return new_object ;
317+ }
318+
319+ ZEND_API zend_object * zend_objects_clone_obj (zend_object * old_object )
320+ {
321+ zend_object * new_object ;
322+
341323 if (UNEXPECTED (zend_object_is_lazy (old_object ))) {
342- return zend_lazy_object_clone (old_object , scope , properties );
324+ return zend_lazy_object_clone (old_object );
343325 }
344326
345327 /* assume that create isn't overwritten, so when clone depends on the
@@ -356,12 +338,7 @@ ZEND_API zend_object *zend_objects_clone_obj_with(zend_object *old_object, const
356338 } while (p != end );
357339 }
358340
359- zend_objects_clone_members_with (new_object , old_object , scope , properties );
341+ zend_objects_clone_members (new_object , old_object );
360342
361343 return new_object ;
362344}
363-
364- ZEND_API zend_object * zend_objects_clone_obj (zend_object * old_object )
365- {
366- return zend_objects_clone_obj_with (old_object , NULL , & zend_empty_array );
367- }
0 commit comments