]> granicus.if.org Git - php/commitdiff
- Fixed magic method and constructor copy for traits
authorFelipe Pena <felipe@php.net>
Fri, 7 May 2010 13:55:27 +0000 (13:55 +0000)
committerFelipe Pena <felipe@php.net>
Fri, 7 May 2010 13:55:27 +0000 (13:55 +0000)
Zend/tests/traits/methods_001.phpt [new file with mode: 0644]
Zend/tests/traits/methods_002.phpt [new file with mode: 0644]
Zend/tests/traits/methods_003.phpt [new file with mode: 0644]
Zend/zend_compile.c

diff --git a/Zend/tests/traits/methods_001.phpt b/Zend/tests/traits/methods_001.phpt
new file mode 100644 (file)
index 0000000..e1ee815
--- /dev/null
@@ -0,0 +1,39 @@
+--TEST--
+Testing magic method on trait
+--FILE--
+<?php
+
+trait foo {    
+       public function __toString() {
+               return '123';
+       }
+       
+       public function __get($x) {
+               var_dump($x);
+       }
+       
+       public function __set($attr, $val) {
+               var_dump($attr .'==='. $val);
+       }
+       
+       public function __clone() {
+               var_dump(__FUNCTION__);
+       }
+}
+
+class bar {
+       use foo;
+}
+
+$o = new bar;
+echo $o, PHP_EOL;
+$o->xyz;
+$o->xyz = 2;
+clone $o;
+
+?>
+--EXPECT--
+123
+string(3) "xyz"
+string(7) "xyz===2"
+string(7) "__clone"
diff --git a/Zend/tests/traits/methods_002.phpt b/Zend/tests/traits/methods_002.phpt
new file mode 100644 (file)
index 0000000..58fbf93
--- /dev/null
@@ -0,0 +1,30 @@
+--TEST--
+Testing collision with magic methods
+--FILE--
+<?php
+
+trait foo {    
+       public function __clone() {
+               var_dump(__FUNCTION__);
+       }
+}
+
+trait baz {
+       public function __clone() {
+               var_dump(__FUNCTION__);
+       }
+}
+
+class bar {
+       use foo;
+       use baz;
+}
+
+$o = new bar;
+var_dump(clone $o);
+
+?>
+--EXPECTF--
+Warning: Trait method __clone has not been applied, because there are collisions with other trait methods on bar in %s on line %d
+object(bar)#%d (0) {
+}
diff --git a/Zend/tests/traits/methods_003.phpt b/Zend/tests/traits/methods_003.phpt
new file mode 100644 (file)
index 0000000..1c1218a
--- /dev/null
@@ -0,0 +1,24 @@
+--TEST--
+Testing __construct and __destruct with Trait
+--FILE--
+<?php
+
+trait foo {    
+       public function __construct() {
+               var_dump(__FUNCTION__);
+       }
+       public function __destruct() {
+               var_dump(__FUNCTION__);
+       }
+}
+
+class bar {
+       use foo;
+}
+
+new bar;
+
+?>
+--EXPECT--
+string(11) "__construct"
+string(10) "__destruct"
index c14ba9fbda4a31180a9f508f68d0deae4ec5e4d0..5d3865fbaee225f3455b841876603a786253373d 100644 (file)
@@ -3329,16 +3329,18 @@ static int zend_traits_merge_functions(zend_function *fn TSRMLS_DC, int num_args
       strncmp(mname, str, mname_len)
 
 #define _ADD_MAGIC_METHOD(ce, mname, mname_len, fe) { \
-       if (IS_EQUAL(mname, mname_len, "__clone"))      {       (ce)->clone                     = (fe); (fe)->common.fn_flags = ZEND_ACC_CLONE; } \
-       else if (IS_EQUAL(mname, mname_len, "__get"))           (ce)->__get                     = (fe); \
-       else if (IS_EQUAL(mname, mname_len, "__set"))           (ce)->__set                     = (fe); \
-       else if (IS_EQUAL(mname, mname_len, "__call"))          (ce)->__call            = (fe); \
-       else if (IS_EQUAL(mname, mname_len, "__unset"))         (ce)->__unset           = (fe); \
-       else if (IS_EQUAL(mname, mname_len, "__isset"))         (ce)->__isset           = (fe); \
-       else if (IS_EQUAL(mname, mname_len, "__callstatic"))(ce)->__callstatic  = (fe); \
-       else if (IS_EQUAL(mname, mname_len, "__tostring"))      (ce)->__tostring        = (fe); \
-       else if (IS_EQUAL(mname, mname_len, "serialize_func"))  (ce)->serialize_func    = (fe); \
-       else if (IS_EQUAL(mname, mname_len, "unserialize_func"))(ce)->unserialize_func  = (fe); \
+       if (!IS_EQUAL(mname, mname_len, "__clone"))     {       (ce)->clone                     = (fe); (fe)->common.fn_flags |= ZEND_ACC_CLONE; } \
+       else if (!IS_EQUAL(mname, mname_len, "__construct"))  {         (ce)->constructor = (fe); (fe)->common.fn_flags |= ZEND_ACC_CTOR; } \
+       else if (!IS_EQUAL(mname, mname_len, "__destruct"))  {          (ce)->destructor = (fe); (fe)->common.fn_flags |= ZEND_ACC_DTOR; } \
+       else if (!IS_EQUAL(mname, mname_len, "__get"))          (ce)->__get                     = (fe); \
+       else if (!IS_EQUAL(mname, mname_len, "__set"))          (ce)->__set                     = (fe); \
+       else if (!IS_EQUAL(mname, mname_len, "__call"))         (ce)->__call            = (fe); \
+       else if (!IS_EQUAL(mname, mname_len, "__unset"))                (ce)->__unset           = (fe); \
+       else if (!IS_EQUAL(mname, mname_len, "__isset"))                (ce)->__isset           = (fe); \
+       else if (!IS_EQUAL(mname, mname_len, "__callstatic"))(ce)->__callstatic = (fe); \
+       else if (!IS_EQUAL(mname, mname_len, "__tostring"))     (ce)->__tostring        = (fe); \
+       else if (!IS_EQUAL(mname, mname_len, "serialize_func")) (ce)->serialize_func    = (fe); \
+       else if (!IS_EQUAL(mname, mname_len, "unserialize_func"))(ce)->unserialize_func = (fe); \
 }
 
 /* {{{ Originates from php_runkit_function_copy_ctor
@@ -3433,6 +3435,7 @@ static int zend_traits_merge_functions_to_class(zend_function *fn TSRMLS_DC, int
        zend_class_entry *ce = va_arg(args, zend_class_entry*);
        int add = 0;
        zend_function* existing_fn;
+       zend_function fn_copy, *fn_copy_p;
        zend_function* prototype = NULL;                /* is used to determine the prototype according to the inheritance chain */
 
        if (zend_hash_quick_find(&ce->function_table, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void**) &existing_fn) == FAILURE) {
@@ -3472,17 +3475,20 @@ static int zend_traits_merge_functions_to_class(zend_function *fn TSRMLS_DC, int
                if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
                        ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
                }
+               fn_copy = *fn;
+               zend_traits_duplicate_function(&fn_copy, estrdup(fn->common.function_name));
 
-               if (zend_hash_quick_update(&ce->function_table, hash_key->arKey, hash_key->nKeyLength, hash_key->h, fn, sizeof(zend_function), NULL)==FAILURE) {
+               if (zend_hash_quick_update(&ce->function_table, hash_key->arKey, hash_key->nKeyLength, hash_key->h, &fn_copy, sizeof(zend_function), (void**)&fn_copy_p)==FAILURE) {
                        zend_error(E_ERROR, "Trait method %s has not been applied, because failure occured during updating class method table", hash_key->arKey);
                }
 
-               _ADD_MAGIC_METHOD(ce, hash_key->arKey, hash_key->nKeyLength, fn);
+               _ADD_MAGIC_METHOD(ce, hash_key->arKey, hash_key->nKeyLength, fn_copy_p);
                /* it could be necessary to update child classes as well */
                /* zend_hash_apply_with_arguments(EG(class_table) TSRMLS_CC, (apply_func_args_t)php_runkit_update_children_methods, 5, dce, dce, &dfe, dfunc, dfunc_len); */
+
+               zend_function_dtor(fn);
        } else {
                zend_function_dtor(fn);
-               /* efree(fn); */
        }
 
        return ZEND_HASH_APPLY_REMOVE;