]> granicus.if.org Git - php/commitdiff
Redesign the clone() feature to fix some fundamental flaws in the previous
authorZeev Suraski <zeev@php.net>
Mon, 2 Feb 2004 12:28:19 +0000 (12:28 +0000)
committerZeev Suraski <zeev@php.net>
Mon, 2 Feb 2004 12:28:19 +0000 (12:28 +0000)
implementation.

Using clone directly is now done using
$replica = clone $src;

Clone methods must now be declared as follows:
function __clone($that)
{
}

Clone methods in derived classes can call the __clone method of their parent
classes using parent::__clone($that)

Zend/zend_compile.c
Zend/zend_compile.h
Zend/zend_language_parser.y
Zend/zend_language_scanner.l
Zend/zend_objects.c

index 9387733f492f8430351d0ae1a1160314fc704326..a5b58f16f62ac685eb0fa2be9f0f110720b5adfc 100644 (file)
@@ -1101,9 +1101,17 @@ void zend_do_end_function_declaration(znode *function_token TSRMLS_DC)
        zend_do_extended_info(TSRMLS_C);
        zend_do_return(NULL, 0 TSRMLS_CC);
        pass_two(CG(active_op_array) TSRMLS_CC);
+
+       if (CG(active_class_entry)
+               && !strcmp(CG(active_op_array)->function_name, ZEND_CLONE_FUNC_NAME)
+               && (CG(active_op_array)->num_args != 1 || strcmp(CG(active_op_array)->arg_info[0].name, "that")!=0)) {
+               zend_error(E_COMPILE_ERROR, "The clone method must be declared as __clone($that)");
+       }
+
        CG(active_op_array)->line_end = zend_get_compiled_lineno(TSRMLS_C);
        CG(active_op_array) = function_token->u.op_array;
 
+
        /* Pop the switch and foreach seperators */
        zend_stack_del_top(&CG(switch_cond_stack));
        zend_stack_del_top(&CG(foreach_copy_stack));
@@ -1192,21 +1200,14 @@ void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC)
 
        if ((last_op->op2.op_type == IS_CONST) && (last_op->op2.u.constant.value.str.len == sizeof(ZEND_CLONE_FUNC_NAME)-1)
                && !zend_binary_strcasecmp(last_op->op2.u.constant.value.str.val, last_op->op2.u.constant.value.str.len, ZEND_CLONE_FUNC_NAME, sizeof(ZEND_CLONE_FUNC_NAME)-1)) {
-               last_op->opcode = ZEND_CLONE;
-               left_bracket->op_type = IS_UNUSED;
-               zval_dtor(&last_op->op2.u.constant); 
-               SET_UNUSED(last_op->op2);
-               left_bracket->u.constant.value.lval = get_next_op_number(CG(active_op_array))-1;
-               zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(zend_function *));
-               zend_do_extended_fcall_begin(TSRMLS_C); 
-               return;
+               zend_error(E_COMPILE_ERROR, "Cannot call __clone() method on objects - use 'clone $obj' instead");
        }
 
        if (last_op->opcode == ZEND_FETCH_OBJ_R) {
                last_op->opcode = ZEND_INIT_METHOD_CALL;
                left_bracket->u.constant.value.lval = ZEND_INIT_FCALL_BY_NAME;
        } else {
-               zend_opopline = get_next_op(CG(active_op_array) TSRMLS_CC);
+               zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
                opline->opcode = ZEND_INIT_FCALL_BY_NAME;
                opline->op2 = *left_bracket;
                opline->extended_value = 0;
@@ -1217,7 +1218,20 @@ void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC)
        zend_do_extended_fcall_begin(TSRMLS_C); 
 }
  
+
+void zend_do_clone(znode *result, znode *expr TSRMLS_DC)
+{
+       zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
+
+       opline->opcode = ZEND_CLONE;
+       opline->op1 = *expr;
+       SET_UNUSED(opline->op2);
+       opline->result.op_type = IS_VAR;
+       opline->result.u.var = get_temporary_variable(CG(active_op_array));
+       *result = opline->result;
+}
+
+
 void zend_do_begin_dynamic_function_call(znode *function_name TSRMLS_DC)
 {
        unsigned char *ptr = NULL;
@@ -1321,7 +1335,6 @@ void zend_do_begin_class_member_function_call(TSRMLS_D)
 void zend_do_end_function_call(znode *function_name, znode *result, znode *argument_list, int is_method, int is_dynamic_fcall TSRMLS_DC)
 {
        zend_op *opline;
-
                
        if (is_method && function_name && function_name->op_type == IS_UNUSED) {
                /* clone */
index e90654b098119c6eb3bf0becc9d986fa4f576966..5f9b775d0057c54244dd48f2f3065799348a7a48 100644 (file)
@@ -345,6 +345,7 @@ void zend_do_end_function_declaration(znode *function_token TSRMLS_DC);
 void zend_do_receive_arg(zend_uchar op, znode *var, znode *offset, znode *initialization, znode *class_type, znode *varname, zend_bool pass_by_reference TSRMLS_DC);
 int zend_do_begin_function_call(znode *function_name TSRMLS_DC);
 void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC);
+void zend_do_clone(znode *result, znode *expr TSRMLS_DC);
 void zend_do_begin_dynamic_function_call(znode *function_name TSRMLS_DC);
 void zend_do_fetch_class(znode *result, znode *class_name TSRMLS_DC);
 void zend_do_fetch_class_name(znode *result, znode *class_entry, znode *class_name TSRMLS_DC);
index f71c1b6712db6939809908a07117ac07ef506219..1987d00fc215da9a3d826a6d2b426b95407fc399 100644 (file)
@@ -69,7 +69,7 @@
 %left '*' '/' '%'
 %right '!' '~' T_INC T_DEC T_INT_CAST T_DOUBLE_CAST T_STRING_CAST T_ARRAY_CAST T_OBJECT_CAST T_BOOL_CAST T_UNSET_CAST '@'
 %right '['
-%nonassoc T_NEW T_INSTANCEOF
+%nonassoc T_NEW T_INSTANCEOF T_CLONE
 %token T_EXIT
 %token T_IF
 %left T_ELSEIF
@@ -519,8 +519,9 @@ expr_without_variable:
                T_LIST '(' { zend_do_list_init(TSRMLS_C); } assignment_list ')' '=' expr { zend_do_list_end(&$$, &$7 TSRMLS_CC); }
        |       variable '=' expr               { zend_check_writable_variable(&$1); zend_do_end_variable_parse(BP_VAR_W, 0 TSRMLS_CC); zend_do_assign(&$$, &$1, &$3 TSRMLS_CC); }
        |       variable '=' '&' variable { zend_do_end_variable_parse(BP_VAR_W, 0 TSRMLS_CC); zend_do_end_variable_parse(BP_VAR_W, 0 TSRMLS_CC); zend_do_assign_ref(&$$, &$1, &$4 TSRMLS_CC); }
-       |       variable '=' '&' T_NEW class_name_reference { zend_check_writable_variable(&$1); zend_do_extended_fcall_begin(TSRMLS_C); zend_do_begin_new_object(&$4, &$5 TSRMLS_CC); } ctor_arguments { zend_do_end_new_object(&$3, &$4, &$7 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); zend_do_end_variable_parse(BP_VAR_W, 0 TSRMLS_CC); zend_do_assign_ref(&$$, &$1, &$3 TSRMLS_CC); }
+       |       variable '=' '&' T_NEW class_name_reference { zend_error(E_STRICT, "Assigning the return value of new by reference is deprecated");  zend_check_writable_variable(&$1); zend_do_extended_fcall_begin(TSRMLS_C); zend_do_begin_new_object(&$4, &$5 TSRMLS_CC); } ctor_arguments { zend_do_end_new_object(&$3, &$4, &$7 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); zend_do_end_variable_parse(BP_VAR_W, 0 TSRMLS_CC); zend_do_assign_ref(&$$, &$1, &$3 TSRMLS_CC); }
        |       T_NEW class_name_reference { zend_do_extended_fcall_begin(TSRMLS_C); zend_do_begin_new_object(&$1, &$2 TSRMLS_CC); } ctor_arguments { zend_do_end_new_object(&$$, &$1, &$4 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);}
+       |       T_CLONE expr { zend_do_clone(&$$, &$2 TSRMLS_CC); }
        |       variable T_PLUS_EQUAL expr      { zend_check_writable_variable(&$1); zend_do_end_variable_parse(BP_VAR_RW, 0 TSRMLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_ADD, &$$, &$1, &$3 TSRMLS_CC); }
        |       variable T_MINUS_EQUAL expr     { zend_check_writable_variable(&$1); zend_do_end_variable_parse(BP_VAR_RW, 0 TSRMLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_SUB, &$$, &$1, &$3 TSRMLS_CC); }
        |       variable T_MUL_EQUAL expr               { zend_check_writable_variable(&$1); zend_do_end_variable_parse(BP_VAR_RW, 0 TSRMLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_MUL, &$$, &$1, &$3 TSRMLS_CC); }
index 8f9a966d00416e78f1958e381f5a17c2d4c56f53..13efdaffab86ecc81410097bc9eaef59eccc0621 100644 (file)
@@ -928,6 +928,10 @@ NEWLINE ("\r"|"\n"|"\r\n")
        return T_NEW;
 }
 
+<ST_IN_SCRIPTING>"clone" {
+       return T_CLONE;
+}
+
 <ST_IN_SCRIPTING>"var" {
        return T_VAR;
 }
index 05595e84e941a364f26cb64db1efabb63274942f..5488511c5c761b3e6344a7090f74d1929fe52ca0 100644 (file)
@@ -108,6 +108,7 @@ ZEND_API void zend_objects_clone_members(zend_object *new_object, zend_object_va
                zval *retval_ptr;
                HashTable symbol_table;
                zend_class_entry *ce = old_object->ce;
+               zval **args[1];
 
                zend_hash_copy(new_object->properties, &ce->default_properties, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
 
@@ -129,9 +130,11 @@ ZEND_API void zend_objects_clone_members(zend_object *new_object, zend_object_va
                clone_func_name->value.str.len = sizeof("__clone")-1;
 
                ZEND_INIT_SYMTABLE(&symbol_table);
-               ZEND_SET_SYMBOL(&symbol_table, "that", old_obj);
+               args[0] = &old_obj;
                
-               call_user_function_ex(NULL, &new_obj, clone_func_name, &retval_ptr, 0, NULL, 0, &symbol_table TSRMLS_CC);
+               call_user_function_ex(NULL, &new_obj, clone_func_name, &retval_ptr, 1, args, 1, &symbol_table TSRMLS_CC);
+
+               zval_ptr_dtor(args[0]);
 
                zend_hash_destroy(&symbol_table);
                zval_ptr_dtor(&new_obj);