@@ -69,6 +69,84 @@ zend_result zend_startup_builtin_functions(void) /* {{{ */
6969}
7070/* }}} */
7171
72+ ZEND_FUNCTION (clone )
73+ {
74+ zend_object * zobj ;
75+ zval * args ;
76+ uint32_t argc ;
77+ HashTable * named_params ;
78+
79+ ZEND_PARSE_PARAMETERS_START (1 , -1 )
80+ Z_PARAM_OBJ (zobj )
81+ Z_PARAM_VARIADIC_WITH_NAMED (args , argc , named_params );
82+ ZEND_PARSE_PARAMETERS_END ();
83+
84+ zend_class_entry * scope = zend_get_executed_scope ();
85+
86+ zend_class_entry * ce = zobj -> ce ;
87+ zend_function * clone = ce -> clone ;
88+
89+ if (UNEXPECTED (zobj -> handlers -> clone_obj == NULL )) {
90+ zend_throw_error (NULL , "Trying to clone an uncloneable object of class %s" , ZSTR_VAL (ce -> name ));
91+ RETURN_THROWS ();
92+ }
93+
94+ if (clone && !(clone -> common .fn_flags & ZEND_ACC_PUBLIC )) {
95+ if (clone -> common .scope != scope ) {
96+ if (UNEXPECTED (clone -> common .fn_flags & ZEND_ACC_PRIVATE )
97+ || UNEXPECTED (!zend_check_protected (zend_get_function_root_class (clone ), scope ))) {
98+ zend_throw_error (NULL , "Call to %s %s::__clone() from %s%s" ,
99+ zend_visibility_string (clone -> common .fn_flags ), ZSTR_VAL (clone -> common .scope -> name ),
100+ scope ? "scope " : "global scope" ,
101+ scope ? ZSTR_VAL (scope -> name ) : ""
102+ );
103+ RETURN_THROWS ();
104+ }
105+ }
106+ }
107+
108+ zend_object * cloned ;
109+ if (zobj -> handlers -> clone_obj_with ) {
110+ HashTable * params = named_params ;
111+ if (UNEXPECTED (argc > 0 )) {
112+ HashTable params ;
113+ zend_hash_init (& params , argc + (named_params ? zend_hash_num_elements (named_params ) : 0 ), NULL , ZVAL_PTR_DTOR , false);
114+ for (uint32_t i = 0 ; i < argc ; i ++ ) {
115+ zend_string * key = zend_long_to_str (i );
116+ zend_hash_update (& params , key , & args [i ]);
117+ zend_string_release (key );
118+ }
119+ if (named_params != NULL ) {
120+ zend_string * key ;
121+ zval * val ;
122+ ZEND_HASH_FOREACH_STR_KEY_VAL (named_params , key , val ) {
123+ zend_hash_update (& params , key , val );
124+ } ZEND_HASH_FOREACH_END ();
125+ }
126+ cloned = zobj -> handlers -> clone_obj_with (zobj , scope , & params );
127+ zend_hash_destroy (& params );
128+ } else {
129+ cloned = zobj -> handlers -> clone_obj_with (zobj , scope , params );
130+ }
131+ } else {
132+ if (UNEXPECTED (named_params || argc > 0 )) {
133+ zend_throw_error (NULL , "Trying to clone an object with updated properties that is not compatible %s" , ZSTR_VAL (ce -> name ));
134+ RETURN_THROWS ();
135+ }
136+ cloned = zobj -> handlers -> clone_obj (zobj );
137+ }
138+
139+ if (EG (exception )) {
140+ if (cloned ) {
141+ OBJ_RELEASE (cloned );
142+ }
143+
144+ RETURN_THROWS ();
145+ }
146+
147+ RETURN_OBJ (cloned );
148+ }
149+
72150ZEND_FUNCTION (exit )
73151{
74152 zend_string * str = NULL ;
0 commit comments