]> granicus.if.org Git - php/commitdiff
Traits refactoring
authorDmitry Stogov <dmitry@zend.com>
Tue, 25 Dec 2012 06:23:08 +0000 (10:23 +0400)
committerDmitry Stogov <dmitry@zend.com>
Tue, 25 Dec 2012 06:23:08 +0000 (10:23 +0400)
18 files changed:
Zend/tests/traits/bug60153.phpt
Zend/tests/traits/bug60217b.phpt
Zend/tests/traits/bug60217c.phpt
Zend/tests/traits/bugs/abstract-methods05.phpt
Zend/tests/traits/bugs/abstract-methods06.phpt
Zend/tests/traits/error_010.phpt
Zend/tests/traits/inheritance003.phpt
Zend/tests/traits/language014.phpt [new file with mode: 0644]
Zend/tests/traits/language015.phpt [new file with mode: 0644]
Zend/tests/traits/language016.phpt [new file with mode: 0644]
Zend/tests/traits/language017.phpt [new file with mode: 0644]
Zend/tests/traits/language018.phpt [new file with mode: 0644]
Zend/tests/traits/language019.phpt [new file with mode: 0644]
Zend/zend.h
Zend/zend_compile.c
Zend/zend_compile.h
Zend/zend_language_parser.y
Zend/zend_opcode.c

index 8f01e72c2d6391f219471e0bf87bbbf4e32377ab..979eced1fb274152f1aedc93a92369621c60833d 100644 (file)
@@ -16,4 +16,4 @@ class C implements IFoo {
 }
 
 --EXPECTF--
-Fatal error: Declaration of C::oneArgument() must be compatible with IFoo::oneArgument($a) in %s on line %d
+Fatal error: Declaration of TFoo::oneArgument() must be compatible with IFoo::oneArgument($a) in %s on line %d
index f03955020ede2b25da39bfa98327ac777a96a1ec..eb852a4fb43c81cd529994c95bc3b0a60e3c9a2b 100644 (file)
@@ -23,4 +23,4 @@ $o = new CBroken;
 $o->foo(1);
 
 --EXPECTF--
-Fatal error: Declaration of TBroken1::foo($a) must be compatible with TBroken2::foo($a, $b = 0) in %s on line %d
+Fatal error: Declaration of TBroken2::foo($a, $b = 0) must be compatible with TBroken1::foo($a) in %s on line %d
index ce8980775f1b3451ace8b121c7170036c5a2edc9..baa4314a61ade348310af12aa852f49e4f52d949 100644 (file)
@@ -23,4 +23,4 @@ $o = new CBroken;
 $o->foo(1);
 
 --EXPECTF--
-Fatal error: Declaration of TBroken1::foo($a, $b = 0) must be compatible with TBroken2::foo($a) in %s on line %d
+Fatal error: Declaration of TBroken2::foo($a) must be compatible with TBroken1::foo($a, $b = 0) in %s on line %d
index e90ce39a32111e820fc5ae49ea581009beb60cba..9a1315f8688d2899b3c52107a6ad3d114419f767 100644 (file)
@@ -22,4 +22,4 @@ class TraitsTest1 {
 
 ?>
 --EXPECTF--    
-Fatal error: Declaration of THelloB::hello() must be compatible with THelloA::hello($a) in %s on line %d
\ No newline at end of file
+Fatal error: Declaration of THelloA::hello($a) must be compatible with THelloB::hello() in %s on line %d
index 28ed672725bb53de92271f71579e8d68c0dcbe78..8569aefb383f3f6a7d93c5ff8629afbe3aa8144a 100644 (file)
@@ -23,4 +23,4 @@ class TraitsTest1 {
 
 ?>
 --EXPECTF--    
-Fatal error: Declaration of THelloA::hello($a) must be compatible with THelloB::hello() in %s on line %d
\ No newline at end of file
+Fatal error: Declaration of THelloB::hello() must be compatible with THelloA::hello($a) in %s on line %d
index 8f3f7dddfd723fab495c87e4a5fb842610369fde..de3741ea572ecaf80b2fb299c0ff44377cefcdaa 100644 (file)
@@ -10,13 +10,9 @@ trait c {
        public function test() { return 2; }
 }
 
-trait b {
-       public function test() { return 1; }
-}
-
 class bar {
-       use foo, c { c::test insteadof foo, b; }
-       use foo, c { c::test insteadof foo, b; }
+       use foo, c { c::test insteadof foo; }
+       use foo, c { c::test insteadof foo; }
 }
 
 $x = new bar;
index a41c4e484aa2df30242e5c892d14998b794ee610..22ff6e243c38db1363b1baab37b197f598b4c711 100644 (file)
@@ -35,4 +35,4 @@ $o->sayHello(array());
 --EXPECTF--    
 World!
 
-Fatal error: Declaration of MyHelloWorld::sayHello() must be compatible with Base::sayHello(array $a) in %s on line %d
+Fatal error: Declaration of SayWorld::sayHello(Base $d) must be compatible with Base::sayHello(array $a) in %s on line %d
diff --git a/Zend/tests/traits/language014.phpt b/Zend/tests/traits/language014.phpt
new file mode 100644 (file)
index 0000000..102b9ae
--- /dev/null
@@ -0,0 +1,30 @@
+--TEST--
+Aliasing leading to conflict should result in error message
+--FILE--
+<?php
+error_reporting(E_ALL);
+
+trait Hello {
+   public function hello() {
+     echo 'Hello';
+   }
+}
+
+trait World {
+   public function world() {
+     echo ' World!';
+   }
+}
+
+
+class MyClass {
+   use Hello, World { world as hello; }
+}
+
+$o = new MyClass();
+$o->hello();
+$o->world();
+
+?>
+--EXPECTF--    
+Fatal error: Trait method hello has not been applied, because there are collisions with other trait methods on MyClass in %s on line %d
diff --git a/Zend/tests/traits/language015.phpt b/Zend/tests/traits/language015.phpt
new file mode 100644 (file)
index 0000000..df1f744
--- /dev/null
@@ -0,0 +1,17 @@
+--TEST--
+Invalid conflict resolution (unused trait as lhs of "insteadof")
+--FILE--
+<?php
+trait T1 {
+       function foo() {echo "T1\n";}
+}
+trait T2 {
+        function foo() {echo "T2\n";}
+}
+class C {
+       use T1 {
+               T2::foo insteadof T1;
+       }
+}
+--EXPECTF--
+Fatal error: Trait T2 is not used in %s on line %d
diff --git a/Zend/tests/traits/language016.phpt b/Zend/tests/traits/language016.phpt
new file mode 100644 (file)
index 0000000..e928119
--- /dev/null
@@ -0,0 +1,17 @@
+--TEST--
+Invalid conflict resolution (unused trait as rhs of "insteadof")
+--FILE--
+<?php
+trait T1 {
+       function foo() {echo "T1\n";}
+}
+trait T2 {
+        function foo() {echo "T2\n";}
+}
+class C {
+       use T1 {
+               T1::foo insteadof T2;
+       }
+}
+--EXPECTF--
+Fatal error: Trait T2 is not used in %s on line %d
diff --git a/Zend/tests/traits/language017.phpt b/Zend/tests/traits/language017.phpt
new file mode 100644 (file)
index 0000000..56f9e24
--- /dev/null
@@ -0,0 +1,17 @@
+--TEST--
+Invalid conflict resolution (unused trait as lhs of "as")
+--FILE--
+<?php
+trait T1 {
+       function foo() {echo "T1\n";}
+}
+trait T2 {
+        function foo() {echo "T2\n";}
+}
+class C {
+       use T1 {
+               T2::foo as private;
+       }
+}
+--EXPECTF--
+Fatal error: Trait T2 is not used in %s on line %d
diff --git a/Zend/tests/traits/language018.phpt b/Zend/tests/traits/language018.phpt
new file mode 100644 (file)
index 0000000..ac36698
--- /dev/null
@@ -0,0 +1,15 @@
+--TEST--
+abstract alias
+--FILE--
+<?php
+trait T1 {
+       function foo() {}
+}
+class C1 {
+       use T1 {
+               T1::foo as abstract;
+       }
+}
+?>
+--EXPECTF--
+Fatal error: Cannot use 'abstarct' as method modifier in %s on line %d
diff --git a/Zend/tests/traits/language019.phpt b/Zend/tests/traits/language019.phpt
new file mode 100644 (file)
index 0000000..83318c5
--- /dev/null
@@ -0,0 +1,15 @@
+--TEST--
+final alias
+--FILE--
+<?php
+trait T1 {
+       function foo() {}
+}
+class C1 {
+       use T1 {
+               T1::foo as final;
+       }
+}
+?>
+--EXPECTF--
+Fatal error: Cannot use 'final' as method modifier in %s on line %d
index 3226f8ce03ec4251ba425b02580f6cb05eeab042..849ad52884e3dc1efe2743b8a3b5e9c6e50fd2ac 100644 (file)
@@ -437,7 +437,7 @@ struct _zend_trait_precedence {
        
        zend_class_entry** exclude_from_classes;
        
-       union _zend_function* function;
+       union _zend_function* function; /* FIXME: kept in 5.4 for BC, not used */
 };
 typedef struct _zend_trait_precedence zend_trait_precedence;
 
@@ -455,7 +455,7 @@ struct _zend_trait_alias {
        */
        zend_uint modifiers;
        
-       union _zend_function* function;
+       union _zend_function* function; /* FIXME: kept in 5.4 for BC, not used */
 };
 typedef struct _zend_trait_alias zend_trait_alias;
 
index 917e0c1097b13e5e8c64c8c306f130c05e034358..d0c74fa5ee15ede69224994da5617438efbcd481 100644 (file)
@@ -3527,8 +3527,7 @@ ZEND_API void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent
 
        if (ce->ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS && ce->type == ZEND_INTERNAL_CLASS) {
                ce->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS;
-       } else if (!(ce->ce_flags & ZEND_ACC_IMPLEMENT_INTERFACES)
-                               && !(ce->ce_flags & ZEND_ACC_IMPLEMENT_TRAITS)) {
+       } else if (!(ce->ce_flags & (ZEND_ACC_IMPLEMENT_INTERFACES|ZEND_ACC_IMPLEMENT_TRAITS))) {
                /* The verification will be done in runtime by ZEND_VERIFY_ABSTRACT_CLASS */
                zend_verify_abstract_class(ce TSRMLS_CC);
        }
@@ -3625,7 +3624,6 @@ ZEND_API void zend_do_implement_trait(zend_class_entry *ce, zend_class_entry *tr
                        }
                }
                ce->traits[ce->num_traits++] = trait;
-               trait->refcount++;
        }
 }
 /* }}} */
@@ -3637,92 +3635,8 @@ static zend_bool zend_traits_method_compatibility_check(zend_function *fn, zend_
        
        return zend_do_perform_implementation_check(fn, other_fn TSRMLS_CC)
                && zend_do_perform_implementation_check(other_fn, fn TSRMLS_CC)
-               && ((fn_flags & ZEND_ACC_FINAL) == (other_flags & ZEND_ACC_FINAL))   /* equal final qualifier */
-               && ((fn_flags & ZEND_ACC_STATIC)== (other_flags & ZEND_ACC_STATIC)); /* equal static qualifier */
-}
-/* }}} */
-
-static int zend_traits_merge_functions(zend_function *fn TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */
-{
-       size_t current;
-       size_t i;
-       size_t count;
-       HashTable* resulting_table;
-       HashTable** function_tables;
-       zend_class_entry *ce;
-       size_t collision = 0;
-       size_t abstract_solved = 0;
-       zend_function* other_trait_fn;
-
-       current                 = va_arg(args, size_t);  /* index of current trait */
-       count                   = va_arg(args, size_t);
-       resulting_table = va_arg(args, HashTable*);
-       function_tables = va_arg(args, HashTable**);
-       ce                              = va_arg(args, zend_class_entry*);
-
-       for (i = 0; i < count; i++) {
-               if (i == current) {
-                       continue; /* just skip this, cause its the table this function is applied on */
-               }
-               
-               if (zend_hash_quick_find(function_tables[i], hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void **)&other_trait_fn) == SUCCESS) {
-                       /* if it is an abstract method, there is no collision */
-                       if (other_trait_fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
-                               /* Make sure they are compatible */
-                               /* In case both are abstract, just check prototype, but need to do that in both directions */
-                               if (!zend_traits_method_compatibility_check(fn, other_trait_fn TSRMLS_CC)) {
-                                       zend_error(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
-                                                                                               zend_get_function_declaration(fn TSRMLS_CC),
-                                                                                               zend_get_function_declaration(other_trait_fn TSRMLS_CC));
-                               }
-                               
-                               /* we can savely free and remove it from other table */
-                               zend_function_dtor(other_trait_fn);
-                               zend_hash_quick_del(function_tables[i], hash_key->arKey, hash_key->nKeyLength, hash_key->h);
-                       } else {
-                               /* if it is not an abstract method, there is still no collision */
-                               /* if fn is an abstract method */
-                               if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
-                                       /* Make sure they are compatible.
-                                          Here, we already know other_trait_fn cannot be abstract, full check ok. */
-                                       if (!zend_traits_method_compatibility_check(fn, other_trait_fn TSRMLS_CC)) {
-                                               zend_error(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
-                                                                                                       zend_get_function_declaration(fn TSRMLS_CC),
-                                                                                                       zend_get_function_declaration(other_trait_fn TSRMLS_CC));
-                                       }
-                                       
-                                       /* just mark as solved, will be added if its own trait is processed */
-                                       abstract_solved = 1;
-                               } else {
-                                       /* but else, we have a collision of non-abstract methods */
-                                       collision++;
-                                       zend_function_dtor(other_trait_fn);
-                                       zend_hash_quick_del(function_tables[i], hash_key->arKey, hash_key->nKeyLength, hash_key->h);
-                               }
-                       }
-               }
-       }
-
-       if (collision) {
-               zend_function* class_fn;
-
-               /* make sure method is not already overridden in class */
-               if (zend_hash_quick_find(&ce->function_table, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void **)&class_fn) == FAILURE
-                       || class_fn->common.scope != ce) {
-                       zend_error(E_COMPILE_ERROR, "Trait method %s has not been applied, because there are collisions with other trait methods on %s", fn->common.function_name, ce->name);
-               }
-
-               zend_function_dtor(fn);
-       } else if (abstract_solved) {
-               zend_function_dtor(fn);
-       } else {
-               /* Add it to result function table */
-               if (zend_hash_quick_add(resulting_table, hash_key->arKey, hash_key->nKeyLength, hash_key->h, fn, sizeof(zend_function), NULL)==FAILURE) {
-                       zend_error(E_COMPILE_ERROR, "Trait method %s has not been applied, because failure occurred during updating resulting trait method table", fn->common.function_name);
-               }
-       }
-
-       return ZEND_HASH_APPLY_REMOVE;
+               && ((fn_flags & (ZEND_ACC_FINAL|ZEND_ACC_STATIC)) == 
+                   (other_flags & (ZEND_ACC_FINAL|ZEND_ACC_STATIC))); /* equal final and static qualifier */
 }
 /* }}} */
 
@@ -3767,66 +3681,84 @@ static void zend_add_magic_methods(zend_class_entry* ce, const char* mname, uint
 }
 /* }}} */
 
-static int zend_traits_merge_functions_to_class(zend_function *fn TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */
+static void zend_add_trait_method(zend_class_entry *ce, const char *name, const char *arKey, uint nKeyLength, zend_function *fn, HashTable **overriden TSRMLS_DC) /* {{{ */
 {
-       zend_class_entry *ce = va_arg(args, zend_class_entry*);
-       zend_function* existing_fn = NULL;
-       zend_function fn_copy, *fn_copy_p;
-       zend_function* prototype = NULL;  /* is used to determine the prototype according to the inheritance chain */
+       zend_function *existing_fn = NULL;
+       ulong h = zend_hash_func(arKey, nKeyLength);
 
-       if (zend_hash_quick_find(&ce->function_table, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void**) &existing_fn) == FAILURE ||
-           existing_fn->common.scope != ce) {
-               /* not found or inherited from other class or interface */
-               zend_function* parent_function;
-
-               if (ce->parent && zend_hash_quick_find(&ce->parent->function_table, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void**) &parent_function) != FAILURE) {
-                       prototype = parent_function; /* ->common.fn_flags |= ZEND_ACC_ABSTRACT; */
-                       
-                       /* we got that method in the parent class, and are going to override it,
-                         except, if the trait is just asking to have an abstract method implemented. */
-                       if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
-                               /* then we clean up an skip this method */
-                               zend_function_dtor(fn);
-                               return ZEND_HASH_APPLY_REMOVE;
+       if (zend_hash_quick_find(&ce->function_table, arKey, nKeyLength, h, (void**) &existing_fn) == SUCCESS) {
+               if (existing_fn->common.scope == ce) {
+                       /* members from the current class override trait methods */
+                       /* use temporary *overriden HashTable to detect hidden conflict */
+                       if (*overriden) {
+                               if (zend_hash_quick_find(*overriden, arKey, nKeyLength, h, (void**) &existing_fn) == SUCCESS) {
+                                       if (existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
+                                               /* Make sure the trait method is compatible with previosly declared abstarct method */
+                                               if (!zend_traits_method_compatibility_check(fn, existing_fn TSRMLS_CC)) {
+                                                       zend_error(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
+                                                               zend_get_function_declaration(fn TSRMLS_CC),
+                                                               zend_get_function_declaration(existing_fn TSRMLS_CC));
+                                               }
+                                       } else if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
+                                               /* Make sure the abstract declaration is compatible with previous declaration */
+                                               if (!zend_traits_method_compatibility_check(existing_fn, fn TSRMLS_CC)) {
+                                                       zend_error(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
+                                                               zend_get_function_declaration(fn TSRMLS_CC),
+                                                               zend_get_function_declaration(existing_fn TSRMLS_CC));
+                                               }
+                                               return;
+                                       }
+                               }
+                       } else {
+                               ALLOC_HASHTABLE(*overriden);
+                               zend_hash_init_ex(*overriden, 2, NULL, NULL, 0, 0);
                        }
-               }
-
-               fn->common.scope = ce;
-               fn->common.prototype = prototype;
-
-               if (prototype
-                       && (prototype->common.fn_flags & ZEND_ACC_IMPLEMENTED_ABSTRACT
-                       || prototype->common.fn_flags & ZEND_ACC_ABSTRACT)) {
-                       fn->common.fn_flags |= ZEND_ACC_IMPLEMENTED_ABSTRACT;
-               } else if (fn->common.fn_flags & ZEND_ACC_IMPLEMENTED_ABSTRACT) {
-                       /* remove ZEND_ACC_IMPLEMENTED_ABSTRACT flag, think it shouldn't be copied to class */
-                       fn->common.fn_flags = fn->common.fn_flags - ZEND_ACC_IMPLEMENTED_ABSTRACT;
-               }
-
-               /* check whether the trait method fullfills the inheritance requirements */
-               if (prototype) {
-                       do_inheritance_check_on_method(fn, prototype TSRMLS_CC);
-               }
-
-               /* one more thing: make sure we properly implement an abstract method */
-               if (existing_fn && existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
-                       prototype = fn->common.prototype;
+                       zend_hash_quick_update(*overriden, arKey, nKeyLength, h, fn, sizeof(zend_function), (void**)&fn);
+                       return;
+               } else if (existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
+                       /* Make sure the trait method is compatible with previosly declared abstarct method */
+                       if (!zend_traits_method_compatibility_check(fn, existing_fn TSRMLS_CC)) {
+                               zend_error(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
+                                       zend_get_function_declaration(fn TSRMLS_CC),
+                                       zend_get_function_declaration(existing_fn TSRMLS_CC));
+                       }
+               } else if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
+                       /* Make sure the abstract declaration is compatible with previous declaration */
+                       if (!zend_traits_method_compatibility_check(existing_fn, fn TSRMLS_CC)) {
+                               zend_error(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
+                                       zend_get_function_declaration(fn TSRMLS_CC),
+                                       zend_get_function_declaration(existing_fn TSRMLS_CC));
+                       }
+                       return;
+               } else if ((existing_fn->common.scope->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {
+                       /* two trais can't define the same non-abstarct method */
+#if 1
+                       zend_error(E_COMPILE_ERROR, "Trait method %s has not been applied, because there are collisions with other trait methods on %s",
+                               name, ce->name);
+#else          /* TODO: better errot message */
+                       zend_error(E_COMPILE_ERROR, "Trait method %s::%s has not been applied as %s::%s, because of collision with %s::%s",
+                               fn->common.scope->name, fn->common.function_name,
+                               ce->name, name,
+                               existing_fn->common.scope->name, existing_fn->common.function_name);
+#endif
+               } else {
+                       /* inherited members are overridden by members inserted by traits */
+                       /* check whether the trait method fullfills the inheritance requirements */
                        do_inheritance_check_on_method(fn, existing_fn TSRMLS_CC);
-                       fn->common.prototype = prototype;
                }
+       }
 
-               /* delete inherited fn if the function to be added is not abstract */
-               if (existing_fn
-                       && existing_fn->common.scope != ce
-                       && (fn->common.fn_flags & ZEND_ACC_ABSTRACT) == 0) {
-                       /* it is just a reference which was added to the subclass while doing
-                          the inheritance, so we can deleted now, and will add the overriding 
-                          method afterwards.
-                          Except, if we try to add an abstract function, then we should not
-                          delete the inherited one */
-                       zend_hash_quick_del(&ce->function_table, hash_key->arKey, hash_key->nKeyLength, hash_key->h);
-               }
+       function_add_ref(fn);
+       zend_hash_quick_update(&ce->function_table, arKey, nKeyLength, h, fn, sizeof(zend_function), (void**)&fn);
+       zend_add_magic_methods(ce, arKey, nKeyLength, fn TSRMLS_CC);
+}
+/* }}} */
 
+static int zend_fixup_trait_method(zend_function *fn, zend_class_entry *ce TSRMLS_DC) /* {{{ */
+{
+       if ((fn->common.scope->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {
+
+               fn->common.scope = ce;
 
                if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
                        ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
@@ -3834,78 +3766,56 @@ static int zend_traits_merge_functions_to_class(zend_function *fn TSRMLS_DC, int
                if (fn->op_array.static_variables) {
                        ce->ce_flags |= ZEND_HAS_STATIC_IN_METHODS;
                }
-               fn_copy = *fn;
-               function_add_ref(&fn_copy);
-
-               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_COMPILE_ERROR, "Trait method %s has not been applied, because failure occurred during updating class method table", hash_key->arKey);
-               }
-
-               zend_add_magic_methods(ce, hash_key->arKey, hash_key->nKeyLength, fn_copy_p TSRMLS_CC);
-
-               zend_function_dtor(fn);
-       } else {
-               zend_function_dtor(fn);
        }
-
-       return ZEND_HASH_APPLY_REMOVE;
+       return ZEND_HASH_APPLY_KEEP;
 }
 /* }}} */
 
 static int zend_traits_copy_functions(zend_function *fn TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */
 {
-       HashTable* target;
-       zend_trait_alias** aliases;
-       HashTable* exclude_table;
-       char* lcname;
-       unsigned int fnname_len;
-       zend_function fn_copy;
-       void* dummy;
-       size_t i = 0;
-
-       target        = va_arg(args, HashTable*);
-       aliases       = va_arg(args, zend_trait_alias**);
+       zend_class_entry  *ce;
+       HashTable         **overriden;
+       zend_trait_alias  *alias, **alias_ptr;
+       HashTable         *exclude_table;
+       char              *lcname;
+       unsigned int       fnname_len;
+       zend_function      fn_copy;
+       void              *dummy;
+
+       ce            = va_arg(args, zend_class_entry*);
+       overriden     = va_arg(args, HashTable**);
        exclude_table = va_arg(args, HashTable*);
-
+       
        fnname_len = strlen(fn->common.function_name);
 
        /* apply aliases which are qualified with a class name, there should not be any ambiguity */
-       if (aliases) {
-               while (aliases[i]) {
+       if (ce->trait_aliases) {
+               alias_ptr = ce->trait_aliases;
+               alias = *alias_ptr;
+               while (alias) {
                        /* Scope unset or equal to the function we compare to, and the alias applies to fn */
-                       if (aliases[i]->alias != NULL
-                               && (!aliases[i]->trait_method->ce || fn->common.scope == aliases[i]->trait_method->ce)
-                               && aliases[i]->trait_method->mname_len == fnname_len
-                               && (zend_binary_strcasecmp(aliases[i]->trait_method->method_name, aliases[i]->trait_method->mname_len, fn->common.function_name, fnname_len) == 0)) {
+                       if (alias->alias != NULL
+                               && (!alias->trait_method->ce || fn->common.scope == alias->trait_method->ce)
+                               && alias->trait_method->mname_len == fnname_len
+                               && (zend_binary_strcasecmp(alias->trait_method->method_name, alias->trait_method->mname_len, fn->common.function_name, fnname_len) == 0)) {
                                fn_copy = *fn;
-                               function_add_ref(&fn_copy);
-                               /* this function_name is never destroyed, because ZEND_ACC_ALIAS
-                                  flag is set */
-                               fn_copy.common.function_name = aliases[i]->alias;
-                               fn_copy.common.fn_flags |= ZEND_ACC_ALIAS;
                                        
                                /* if it is 0, no modifieres has been changed */
-                               if (aliases[i]->modifiers) { 
-                                       fn_copy.common.fn_flags = aliases[i]->modifiers | ZEND_ACC_ALIAS;
-                                       if (!(aliases[i]->modifiers & ZEND_ACC_PPP_MASK)) {
-                                               fn_copy.common.fn_flags |= ZEND_ACC_PUBLIC;
-                                       }
-                                       fn_copy.common.fn_flags |= fn->common.fn_flags ^ (fn->common.fn_flags & ZEND_ACC_PPP_MASK);
+                               if (alias->modifiers) { 
+                                       fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags ^ (fn->common.fn_flags & ZEND_ACC_PPP_MASK));
                                }
 
-                               lcname = zend_str_tolower_dup(aliases[i]->alias, aliases[i]->alias_len);
-
-                               if (zend_hash_add(target, lcname, aliases[i]->alias_len+1, &fn_copy, sizeof(zend_function), NULL)==FAILURE) {
-                                       zend_error(E_COMPILE_ERROR, "Failed to add aliased trait method (%s) to the trait table. There is probably already a trait method with the same name", fn_copy.common.function_name);
-                               }
+                               lcname = zend_str_tolower_dup(alias->alias, alias->alias_len);
+                               zend_add_trait_method(ce, alias->alias, lcname, alias->alias_len+1, &fn_copy, overriden TSRMLS_DC);
                                efree(lcname);
 
-                               /** Record the trait from which this alias was resolved. */
-                               if (!aliases[i]->trait_method->ce) {
-                                       aliases[i]->trait_method->ce = fn->common.scope;
+                               /* Record the trait from which this alias was resolved. */
+                               if (!alias->trait_method->ce) {
+                                       alias->trait_method->ce = fn->common.scope;
                                }
                        }
-                       i++;
+                       alias_ptr++;
+                       alias = *alias_ptr;
                }
        }
 
@@ -3914,38 +3824,31 @@ static int zend_traits_copy_functions(zend_function *fn TSRMLS_DC, int num_args,
        if (exclude_table == NULL || zend_hash_find(exclude_table, lcname, fnname_len, &dummy) == FAILURE) {
                /* is not in hashtable, thus, function is not to be excluded */
                fn_copy = *fn;
-               function_add_ref(&fn_copy);
-               fn_copy.common.fn_flags |= ZEND_ACC_ALIAS;
-
-               /* apply aliases which are not qualified by a class name, or which have not
-                * alias name, just setting visibility */
-               if (aliases) {
-                       i = 0;
-                       while (aliases[i]) {
+
+               /* apply aliases which have not alias name, just setting visibility */
+               if (ce->trait_aliases) {
+                       alias_ptr = ce->trait_aliases;
+                       alias = *alias_ptr;
+                       while (alias) {
                                /* Scope unset or equal to the function we compare to, and the alias applies to fn */
-                               if (aliases[i]->alias == NULL && aliases[i]->modifiers != 0
-                                       && (!aliases[i]->trait_method->ce || fn->common.scope == aliases[i]->trait_method->ce)
-                                       && (aliases[i]->trait_method->mname_len == fnname_len)
-                                       && (zend_binary_strcasecmp(aliases[i]->trait_method->method_name, aliases[i]->trait_method->mname_len, fn->common.function_name, fnname_len) == 0)) {
-                                       fn_copy.common.fn_flags = aliases[i]->modifiers | ZEND_ACC_ALIAS;
-
-                                       if (!(aliases[i]->modifiers & ZEND_ACC_PPP_MASK)) {
-                                               fn_copy.common.fn_flags |= ZEND_ACC_PUBLIC;
-                                       }
-                                       fn_copy.common.fn_flags |= fn->common.fn_flags ^ (fn->common.fn_flags & ZEND_ACC_PPP_MASK);
+                               if (alias->alias == NULL && alias->modifiers != 0
+                                       && (!alias->trait_method->ce || fn->common.scope == alias->trait_method->ce)
+                                       && (alias->trait_method->mname_len == fnname_len)
+                                       && (zend_binary_strcasecmp(alias->trait_method->method_name, alias->trait_method->mname_len, fn->common.function_name, fnname_len) == 0)) {
+
+                                       fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags ^ (fn->common.fn_flags & ZEND_ACC_PPP_MASK));
 
                                        /** Record the trait from which this alias was resolved. */
-                                       if (!aliases[i]->trait_method->ce) {
-                                               aliases[i]->trait_method->ce = fn->common.scope;
+                                       if (!alias->trait_method->ce) {
+                                               alias->trait_method->ce = fn->common.scope;
                                        }
                                }
-                               i++;
+                               alias_ptr++;
+                               alias = *alias_ptr;
                        }
                }
 
-               if (zend_hash_add(target, lcname, fnname_len+1, &fn_copy, sizeof(zend_function), NULL)==FAILURE) {
-                       zend_error(E_COMPILE_ERROR, "Failed to add trait method (%s) to the trait table. There is probably already a trait method with the same name", fn_copy.common.function_name);
-               }
+               zend_add_trait_method(ce, fn->common.function_name, lcname, fnname_len+1, &fn_copy, overriden TSRMLS_DC);
        }
 
        efree(lcname);
@@ -3954,10 +3857,16 @@ static int zend_traits_copy_functions(zend_function *fn TSRMLS_DC, int num_args,
 }
 /* }}} */
 
-/* Copies function table entries to target function table with applied aliasing */
-static void zend_traits_copy_trait_function_table(HashTable *target, HashTable *source, zend_trait_alias** aliases, HashTable* exclude_table TSRMLS_DC) /* {{{ */
+static void zend_check_trait_usage(zend_class_entry *ce, zend_class_entry *trait TSRMLS_DC) /* {{{ */
 {
-       zend_hash_apply_with_arguments(source TSRMLS_CC, (apply_func_args_t)zend_traits_copy_functions, 3, target, aliases, exclude_table);
+       zend_uint i;
+
+       for (i = 0; i < ce->num_traits; i++) {
+               if (ce->traits[i] == trait) {
+                       return;
+               }
+       }
+       zend_error(E_COMPILE_ERROR, "Trait %s is not used", trait->name);
 }
 /* }}} */
 
@@ -3980,6 +3889,7 @@ static void zend_traits_init_trait_structures(zend_class_entry *ce TSRMLS_DC) /*
                                                                ZEND_FETCH_CLASS_TRAIT|ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC))) {
                                        zend_error(E_COMPILE_ERROR, "Could not find trait %s", cur_method_ref->class_name);
                                }
+                               zend_check_trait_usage(ce, cur_precedence->trait_method->ce TSRMLS_CC);
 
                                /** Ensure that the prefered method is actually available. */
                                lcname = zend_str_tolower_dup(cur_method_ref->method_name,
@@ -4008,8 +3918,9 @@ static void zend_traits_init_trait_structures(zend_class_entry *ce TSRMLS_DC) /*
 
                                        if (!(cur_precedence->exclude_from_classes[j] = zend_fetch_class(class_name, name_length, ZEND_FETCH_CLASS_TRAIT |ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC))) {
                                                zend_error(E_COMPILE_ERROR, "Could not find trait %s", class_name);
-                                       }
-                                       
+                                       }                                       
+                                       zend_check_trait_usage(ce, cur_precedence->exclude_from_classes[j] TSRMLS_CC);
+
                                        /* make sure that the trait method is not from a class mentioned in
                                         exclude_from_classes, for consistency */
                                        if (cur_precedence->trait_method->ce == cur_precedence->exclude_from_classes[i]) {
@@ -4038,6 +3949,7 @@ static void zend_traits_init_trait_structures(zend_class_entry *ce TSRMLS_DC) /*
                                if (!(cur_method_ref->ce = zend_fetch_class(cur_method_ref->class_name, cur_method_ref->cname_len, ZEND_FETCH_CLASS_TRAIT|ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC))) {
                                        zend_error(E_COMPILE_ERROR, "Could not find trait %s", cur_method_ref->class_name);
                                }
+                               zend_check_trait_usage(ce, cur_method_ref->ce TSRMLS_CC);
 
                                /** And, ensure that the referenced method is resolvable, too. */
                                lcname = zend_str_tolower_dup(cur_method_ref->method_name,
@@ -4087,122 +3999,49 @@ static void zend_traits_compile_exclude_table(HashTable* exclude_table, zend_tra
 
 static void zend_do_traits_method_binding(zend_class_entry *ce TSRMLS_DC) /* {{{ */
 {
-       HashTable** function_tables;
-       HashTable* resulting_table;
-       HashTable exclude_table;
-       size_t i;
+       zend_uint i;
+       HashTable *overriden = NULL;
 
-       /* prepare copies of trait function tables for combination */
-       function_tables = emalloc(sizeof(HashTable*) * ce->num_traits);
-       resulting_table = (HashTable *)emalloc(sizeof(HashTable));
-       
-       /* TODO: revisit this start size, may be its not optimal */
-       zend_hash_init_ex(resulting_table, 10, NULL, NULL, 0, 0);
-  
        for (i = 0; i < ce->num_traits; i++) {
-               function_tables[i] = (HashTable *)emalloc(sizeof(HashTable));
-               zend_hash_init_ex(function_tables[i], ce->traits[i]->function_table.nNumOfElements, NULL, NULL, 1, 0);
-
                if (ce->trait_precedences) {
+                       HashTable exclude_table;
+
                        /* TODO: revisit this start size, may be its not optimal */
                        zend_hash_init_ex(&exclude_table, 2, NULL, NULL, 0, 0);
 
                        zend_traits_compile_exclude_table(&exclude_table, ce->trait_precedences, ce->traits[i]);
 
                        /* copies functions, applies defined aliasing, and excludes unused trait methods */
-                       zend_traits_copy_trait_function_table(function_tables[i], &ce->traits[i]->function_table, ce->trait_aliases, &exclude_table TSRMLS_CC);
+                       zend_hash_apply_with_arguments(&ce->traits[i]->function_table TSRMLS_CC, (apply_func_args_t)zend_traits_copy_functions, 3, ce, &overriden, &exclude_table);
+
                        zend_hash_destroy(&exclude_table);
                } else {
-                       zend_traits_copy_trait_function_table(function_tables[i], &ce->traits[i]->function_table, ce->trait_aliases, NULL TSRMLS_CC);
+                       zend_hash_apply_with_arguments(&ce->traits[i]->function_table TSRMLS_CC, (apply_func_args_t)zend_traits_copy_functions, 3, ce, &overriden, NULL);
                }
        }
   
-       /* now merge trait methods */
-       for (i = 0; i < ce->num_traits; i++) {
-               zend_hash_apply_with_arguments(function_tables[i] TSRMLS_CC, (apply_func_args_t)zend_traits_merge_functions, 5, i, ce->num_traits, resulting_table, function_tables, ce);
-       }
-  
-       /* Now the resulting_table contains all trait methods we would have to
-        * add to the class in the following step the methods are inserted into the method table
-        * if there is already a method with the same name it is replaced iff ce != fn.scope
-        * --> all inherited methods are overridden, methods defined in the class are left untouched
-        */
-       zend_hash_apply_with_arguments(resulting_table TSRMLS_CC, (apply_func_args_t)zend_traits_merge_functions_to_class, 1, ce);
-  
-       /* free temporary function tables */
-       for (i = 0; i < ce->num_traits; i++) {
-               /* zend_hash_destroy(function_tables[i]); */
-               zend_hash_graceful_destroy(function_tables[i]);
-               efree(function_tables[i]);
-       }
-       efree(function_tables);
+    zend_hash_apply_with_argument(&ce->function_table, (apply_func_arg_t)zend_fixup_trait_method, ce TSRMLS_CC);
 
-       /* free temporary resulting table */
-       /* zend_hash_destroy(resulting_table); */
-       zend_hash_graceful_destroy(resulting_table);
-       efree(resulting_table);
+       if (overriden) {
+               zend_hash_destroy(overriden);
+               FREE_HASHTABLE(overriden);
+       }
 }
 /* }}} */
 
 static zend_class_entry* find_first_definition(zend_class_entry *ce, size_t current_trait, const char* prop_name, int prop_name_length, ulong prop_hash, zend_class_entry *coliding_ce) /* {{{ */
 {
        size_t i;
-       zend_property_info *coliding_prop;
-       for (i = 0; (i < current_trait) && (i < ce->num_traits); i++) {
-               if (zend_hash_quick_find(&ce->traits[i]->properties_info, prop_name, prop_name_length+1, prop_hash, (void **) &coliding_prop) == SUCCESS) {
-                       return ce->traits[i];
-               }
-       }
-
-       return coliding_ce;
-}
-/* }}} */
 
-static void zend_traits_register_private_property(zend_class_entry *ce, const char *name, int name_len, zend_property_info *old_info, zval *property TSRMLS_DC) /* {{{ */
-{
-       char *priv_name;
-       int priv_name_length;
-       const char *interned_name;
-       zend_property_info property_info;
-       ulong h = zend_get_hash_value(name, name_len+1);
-       property_info = *old_info;
-
-       if (old_info->flags & ZEND_ACC_STATIC) {
-               property_info.offset = ce->default_static_members_count++;
-               ce->default_static_members_table = perealloc(ce->default_static_members_table, sizeof(zval*) * ce->default_static_members_count, ce->type == ZEND_INTERNAL_CLASS);
-               ce->default_static_members_table[property_info.offset] = property;
-               if (ce->type == ZEND_USER_CLASS) {
-                       ce->static_members_table = ce->default_static_members_table;
-               }
-       } else {
-               property_info.offset = ce->default_properties_count++;
-               ce->default_properties_table = perealloc(ce->default_properties_table, sizeof(zval*) * ce->default_properties_count, ce->type == ZEND_INTERNAL_CLASS);
-               ce->default_properties_table[property_info.offset] = property;
-       }
-
-       zend_mangle_property_name(&priv_name, &priv_name_length, ce->name, ce->name_length, name, name_len, ce->type & ZEND_INTERNAL_CLASS);
-       property_info.name = priv_name;
-       property_info.name_length = priv_name_length;
-
-       interned_name = zend_new_interned_string(property_info.name, property_info.name_length+1, 0 TSRMLS_CC);
-       if (interned_name != property_info.name) {
-               if (ce->type == ZEND_USER_CLASS) {
-                       efree((char*)property_info.name);
-               } else {
-                       free((char*)property_info.name);
+       if (coliding_ce == ce) {
+               for (i = 0; i < current_trait; i++) {
+                       if (zend_hash_quick_exists(&ce->traits[i]->properties_info, prop_name, prop_name_length+1, prop_hash)) {
+                               return ce->traits[i];
+                       }
                }
-               property_info.name = interned_name;
-       }
-
-       property_info.h = zend_get_hash_value(property_info.name, property_info.name_length+1);
-
-       property_info.ce = ce;
-
-       if (property_info.doc_comment) {
-               property_info.doc_comment = estrndup(property_info.doc_comment, property_info.doc_comment_len);
        }
 
-       zend_hash_quick_update(&ce->properties_info, name, name_len+1, h, &property_info, sizeof(zend_property_info), NULL);
+       return coliding_ce;
 }
 /* }}} */
 
@@ -4219,7 +4058,8 @@ static void zend_do_traits_property_binding(zend_class_entry *ce TSRMLS_DC) /* {
        zend_bool not_compatible;
        zval* prop_value;
        char* doc_comment;  
-  
+       zend_uint flags;
+
        /* In the following steps the properties are inserted into the property table
         * for that, a very strict approach is applied:
         * - check for compatibility, if not compatible with any property in class -> fatal
@@ -4232,7 +4072,8 @@ static void zend_do_traits_property_binding(zend_class_entry *ce TSRMLS_DC) /* {
                        /* first get the unmangeld name if necessary,
                         * then check whether the property is already there
                         */
-                       if ((property_info->flags & ZEND_ACC_PPP_MASK) == ZEND_ACC_PUBLIC) {
+                       flags = property_info->flags;
+                       if ((flags & ZEND_ACC_PPP_MASK) == ZEND_ACC_PUBLIC) {
                                prop_hash = property_info->h;
                                prop_name = property_info->name;
                                prop_name_length = property_info->name_length;
@@ -4246,61 +4087,50 @@ static void zend_do_traits_property_binding(zend_class_entry *ce TSRMLS_DC) /* {
 
                        /* next: check for conflicts with current class */
                        if (zend_hash_quick_find(&ce->properties_info, prop_name, prop_name_length+1, prop_hash, (void **) &coliding_prop) == SUCCESS) {
-                               if (coliding_prop->flags & ZEND_ACC_SHADOW) {
-                                       /* this one is inherited, lets look it up in its own class */
-                                       zend_hash_quick_find(&coliding_prop->ce->properties_info, prop_name, prop_name_length+1, prop_hash, (void **) &coliding_prop);
-                                       if (coliding_prop->flags & ZEND_ACC_PRIVATE) {
-                                               /* private property, make the property_info.offset indenpended */
-                                               if (property_info->flags & ZEND_ACC_STATIC) {
-                                                       prop_value = ce->traits[i]->default_static_members_table[property_info->offset];
+                               if (coliding_prop->flags & ZEND_ACC_SHADOW) {                                   
+                                       zend_hash_quick_del(&ce->properties_info, prop_name, prop_name_length+1, prop_hash);
+                                       flags |= ZEND_ACC_CHANGED;
+                               } else {                                
+                                       if ((coliding_prop->flags & (ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC))
+                                               == (flags & (ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC))) {
+                                               /* flags are identical, now the value needs to be checked */
+                                               if (flags & ZEND_ACC_STATIC) {
+                                                       not_compatible = (FAILURE == compare_function(&compare_result,
+                                                                                         ce->default_static_members_table[coliding_prop->offset],
+                                                                                         ce->traits[i]->default_static_members_table[property_info->offset] TSRMLS_CC))
+                                                                 || (Z_LVAL(compare_result) != 0);
                                                } else {
-                                                       prop_value = ce->traits[i]->default_properties_table[property_info->offset];
+                                                       not_compatible = (FAILURE == compare_function(&compare_result,
+                                                                                         ce->default_properties_table[coliding_prop->offset],
+                                                                                         ce->traits[i]->default_properties_table[property_info->offset] TSRMLS_CC))
+                                                                 || (Z_LVAL(compare_result) != 0);
                                                }
-                                               Z_ADDREF_P(prop_value);
-
-                                               zend_traits_register_private_property(ce, prop_name, prop_name_length, property_info, prop_value TSRMLS_CC);
-                                               continue;
-                                       }
-                               }
-                               
-                               if ((coliding_prop->flags & (ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC))
-                                       == (property_info->flags & (ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC))) {
-                                       /* flags are identical, now the value needs to be checked */
-                                       if (property_info->flags & ZEND_ACC_STATIC) {
-                                               not_compatible = (FAILURE == compare_function(&compare_result,
-                                                                                 ce->default_static_members_table[coliding_prop->offset],
-                                                                                 ce->traits[i]->default_static_members_table[property_info->offset] TSRMLS_CC))
-                                                         || (Z_LVAL(compare_result) != 0);
                                        } else {
-                                               not_compatible = (FAILURE == compare_function(&compare_result,
-                                                                                 ce->default_properties_table[coliding_prop->offset],
-                                                                                 ce->traits[i]->default_properties_table[property_info->offset] TSRMLS_CC))
-                                                         || (Z_LVAL(compare_result) != 0);
+                                               /* the flags are not identical, thus, we assume properties are not compatible */
+                                               not_compatible = 1;
                                        }
-                               } else {
-                                       /* the flags are not identical, thus, we assume properties are not compatible */
-                                       not_compatible = 1;
-                               }
 
-                               if (not_compatible) {
-                                       zend_error(E_COMPILE_ERROR, 
+                                       if (not_compatible) {
+                                               zend_error(E_COMPILE_ERROR, 
                                                           "%s and %s define the same property ($%s) in the composition of %s. However, the definition differs and is considered incompatible. Class was composed",
                                                                find_first_definition(ce, i, prop_name, prop_name_length, prop_hash, coliding_prop->ce)->name,
                                                                property_info->ce->name,
                                                                prop_name,
                                                                ce->name);
-                               } else {
-                                       zend_error(E_STRICT, 
+                                       } else {
+                                               zend_error(E_STRICT, 
                                                           "%s and %s define the same property ($%s) in the composition of %s. This might be incompatible, to improve maintainability consider using accessor methods in traits instead. Class was composed",
                                                                find_first_definition(ce, i, prop_name, prop_name_length, prop_hash, coliding_prop->ce)->name,
                                                                property_info->ce->name,
                                                                prop_name,
                                                                ce->name);
+                                               continue;
+                                       }
                                }
                        }
 
                        /* property not found, so lets add it */
-                       if (property_info->flags & ZEND_ACC_STATIC) {
+                       if (flags & ZEND_ACC_STATIC) {
                                prop_value = ce->traits[i]->default_static_members_table[property_info->offset];
                        } else {
                                prop_value = ce->traits[i]->default_properties_table[property_info->offset];
@@ -4309,7 +4139,7 @@ static void zend_do_traits_property_binding(zend_class_entry *ce TSRMLS_DC) /* {
 
                        doc_comment = property_info->doc_comment ? estrndup(property_info->doc_comment, property_info->doc_comment_len) : NULL;
                        zend_declare_property_ex(ce, prop_name, prop_name_length, 
-                                                                        prop_value, property_info->flags, 
+                                                                        prop_value, flags, 
                                                                     doc_comment, property_info->doc_comment_len TSRMLS_CC);
                }
        }
@@ -4433,20 +4263,6 @@ ZEND_API int do_bind_function(const zend_op_array *op_array, zend_op *opline, Ha
 }
 /* }}} */
 
-void zend_add_trait_precedence(znode *precedence_znode TSRMLS_DC) /* {{{ */
-{
-       zend_class_entry *ce = CG(active_class_entry);
-       zend_add_to_list(&ce->trait_precedences, precedence_znode->u.op.ptr TSRMLS_CC);
-}
-/* }}} */
-
-void zend_add_trait_alias(znode *alias_znode TSRMLS_DC) /* {{{ */
-{
-       zend_class_entry *ce = CG(active_class_entry);
-       zend_add_to_list(&ce->trait_aliases, alias_znode->u.op.ptr TSRMLS_CC);
-}
-/* }}} */
-
 void zend_prepare_reference(znode *result, znode *class_name, znode *method_name TSRMLS_DC) /* {{{ */
 {
        zend_trait_method_reference *method_ref = emalloc(sizeof(zend_trait_method_reference));
@@ -4471,18 +4287,25 @@ void zend_prepare_reference(znode *result, znode *class_name, znode *method_name
 }
 /* }}} */
 
-void zend_prepare_trait_alias(znode *result, znode *method_reference, znode *modifiers, znode *alias TSRMLS_DC) /* {{{ */
+void zend_add_trait_alias(znode *method_reference, znode *modifiers, znode *alias TSRMLS_DC) /* {{{ */
 {
-       zend_trait_alias *trait_alias = emalloc(sizeof(zend_trait_alias));
+       zend_class_entry *ce = CG(active_class_entry);
+       zend_trait_alias *trait_alias;
 
-       trait_alias->trait_method = (zend_trait_method_reference*)method_reference->u.op.ptr;
-       trait_alias->modifiers = Z_LVAL(modifiers->u.constant);
-       
        if (Z_LVAL(modifiers->u.constant) == ZEND_ACC_STATIC) {
                zend_error(E_COMPILE_ERROR, "Cannot use 'static' as method modifier");
                return;
+       } else if (Z_LVAL(modifiers->u.constant) == ZEND_ACC_ABSTRACT) {
+               zend_error(E_COMPILE_ERROR, "Cannot use 'abstarct' as method modifier");
+               return;
+       } else if (Z_LVAL(modifiers->u.constant) == ZEND_ACC_FINAL) {
+               zend_error(E_COMPILE_ERROR, "Cannot use 'final' as method modifier");
+               return;
        }
 
+       trait_alias = emalloc(sizeof(zend_trait_alias));
+       trait_alias->trait_method = (zend_trait_method_reference*)method_reference->u.op.ptr;
+       trait_alias->modifiers = Z_LVAL(modifiers->u.constant);
        if (alias) {
                trait_alias->alias = Z_STRVAL(alias->u.constant);
                trait_alias->alias_len = Z_STRLEN(alias->u.constant);
@@ -4491,12 +4314,13 @@ void zend_prepare_trait_alias(znode *result, znode *method_reference, znode *mod
        }
        trait_alias->function = NULL;
 
-       result->u.op.ptr = trait_alias;
+       zend_add_to_list(&ce->trait_aliases, trait_alias TSRMLS_CC);
 }
 /* }}} */
 
-void zend_prepare_trait_precedence(znode *result, znode *method_reference, znode *trait_list TSRMLS_DC) /* {{{ */
+void zend_add_trait_precedence(znode *method_reference, znode *trait_list TSRMLS_DC) /* {{{ */
 {
+       zend_class_entry *ce = CG(active_class_entry);
        zend_trait_precedence *trait_precedence = emalloc(sizeof(zend_trait_precedence));
 
        trait_precedence->trait_method = (zend_trait_method_reference*)method_reference->u.op.ptr;
@@ -4504,7 +4328,7 @@ void zend_prepare_trait_precedence(znode *result, znode *method_reference, znode
 
        trait_precedence->function = NULL;
 
-       result->u.op.ptr = trait_precedence;
+       zend_add_to_list(&ce->trait_precedences, trait_precedence TSRMLS_CC);
 }
 /* }}} */
 
@@ -4539,7 +4363,7 @@ ZEND_API zend_class_entry *do_bind_class(const zend_op_array* op_array, const ze
                }
                return NULL;
        } else {
-               if (!(ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_IMPLEMENT_INTERFACES))) {
+               if (!(ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_IMPLEMENT_INTERFACES|ZEND_ACC_IMPLEMENT_TRAITS))) {
                        zend_verify_abstract_class(ce TSRMLS_CC);
                }
                return ce;
@@ -5109,7 +4933,7 @@ void zend_do_end_class_declaration(const znode *class_token, const znode *parent
        if (!(ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS))
                && ((parent_token->op_type != IS_UNUSED) || (ce->num_interfaces > 0))) {
                zend_verify_abstract_class(ce TSRMLS_CC);
-               if (ce->num_interfaces) {
+               if (ce->num_interfaces && !(ce->ce_flags & ZEND_ACC_IMPLEMENT_TRAITS)) {
                        do_verify_abstract_class(TSRMLS_C);
                }
        }
@@ -5159,9 +4983,10 @@ void zend_do_implements_interface(znode *interface_name TSRMLS_DC) /* {{{ */
 }
 /* }}} */
 
-void zend_do_implements_trait(znode *trait_name TSRMLS_DC) /* {{{ */
+void zend_do_use_trait(znode *trait_name TSRMLS_DC) /* {{{ */
 {
        zend_op *opline;
+
        if ((CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE)) {
                zend_error(E_COMPILE_ERROR,
                                "Cannot use traits inside of interfaces. %s is used in %s",
@@ -5891,7 +5716,11 @@ void zend_add_to_list(void *result, void *item TSRMLS_DC) /* {{{ */
        void** list = *(void**)result;
        size_t n = 0;
 
-       while (list && list[n]) { n++; }
+       if (list) {
+               while (list[n]) {
+                       n++;
+               }
+       }
 
        list = erealloc(list, sizeof(void*) * (n+2));
 
index 79ace0c3c3eb05a92e201d401c0cdc0cbae97b4a..b887a78e991c01d1f5e632a0f6afd35caf50c2e9 100644 (file)
@@ -207,8 +207,6 @@ typedef struct _zend_try_catch_element {
 #define ZEND_ACC_RETURN_REFERENCE              0x4000000
 #define ZEND_ACC_DONE_PASS_TWO                 0x8000000
 
-#define ZEND_ACC_ALIAS                                 0x10000000
-
 char *zend_visibility_string(zend_uint fn_flags);
 
 
@@ -509,16 +507,13 @@ ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry
 void zend_do_implements_interface(znode *interface_znode TSRMLS_DC);
 
 /* Trait related functions */
-void zend_add_trait_precedence(znode *precedence_znode TSRMLS_DC);
-void zend_add_trait_alias(znode *alias_znode TSRMLS_DC);
-
+void zend_do_use_trait(znode *trait_znode TSRMLS_DC);
+void zend_prepare_reference(znode *result, znode *class_name, znode *method_name TSRMLS_DC);
+void zend_add_trait_precedence(znode *method_reference, znode *trait_list TSRMLS_DC);
+void zend_add_trait_alias(znode *method_reference, znode *modifiers, znode *alias TSRMLS_DC);
 
-void zend_do_implements_trait(znode *interface_znode /*, znode* aliases */ TSRMLS_DC);
 ZEND_API void zend_do_implement_trait(zend_class_entry *ce, zend_class_entry *trait TSRMLS_DC);
 ZEND_API void zend_do_bind_traits(zend_class_entry *ce TSRMLS_DC);
-void zend_prepare_trait_precedence(znode *result, znode *method_reference, znode *trait_list TSRMLS_DC);
-void zend_prepare_reference(znode *result, znode *class_name, znode *method_name TSRMLS_DC);
-void zend_prepare_trait_alias(znode *result, znode *method_reference, znode *modifiers, znode *alias TSRMLS_DC);
 
 ZEND_API void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent_ce TSRMLS_DC);
 void zend_do_early_binding(TSRMLS_D);
index 9a0b3209e5b4b214ee73de5c7aae8b5b48de46ad..92f25f06ed6c100a80b15f613f00cd52fd90771a 100644 (file)
@@ -585,8 +585,8 @@ trait_use_statement:
 ;
 
 trait_list:
-               fully_qualified_class_name                                              { zend_do_implements_trait(&$1 TSRMLS_CC); }
-       |       trait_list ',' fully_qualified_class_name               { zend_do_implements_trait(&$3 TSRMLS_CC); }
+               fully_qualified_class_name                                              { zend_do_use_trait(&$1 TSRMLS_CC); }
+       |       trait_list ',' fully_qualified_class_name               { zend_do_use_trait(&$3 TSRMLS_CC); }
 ;
 
 trait_adaptations:
@@ -605,12 +605,12 @@ non_empty_trait_adaptation_list:
 ;
 
 trait_adaptation_statement:
-               trait_precedence ';'                                                            { zend_add_trait_precedence(&$1 TSRMLS_CC); }
-       |       trait_alias ';'                                                                         { zend_add_trait_alias(&$1 TSRMLS_CC); }
+               trait_precedence ';'
+       |       trait_alias ';'
 ;
 
 trait_precedence:
-       trait_method_reference_fully_qualified T_INSTEADOF trait_reference_list { zend_prepare_trait_precedence(&$$, &$1, &$3 TSRMLS_CC); }
+       trait_method_reference_fully_qualified T_INSTEADOF trait_reference_list { zend_add_trait_precedence(&$1, &$3 TSRMLS_CC); }
 ;
 
 trait_reference_list:
@@ -628,8 +628,8 @@ trait_method_reference_fully_qualified:
 ;
 
 trait_alias:
-               trait_method_reference T_AS trait_modifiers T_STRING            { zend_prepare_trait_alias(&$$, &$1, &$3, &$4 TSRMLS_CC); }
-       |       trait_method_reference T_AS member_modifier                                     { zend_prepare_trait_alias(&$$, &$1, &$3, NULL TSRMLS_CC); }
+               trait_method_reference T_AS trait_modifiers T_STRING            { zend_add_trait_alias(&$1, &$3, &$4 TSRMLS_CC); }
+       |       trait_method_reference T_AS member_modifier                                     { zend_add_trait_alias(&$1, &$3, NULL TSRMLS_CC); }
 ;
 
 trait_modifiers:
index 4c6a784a8818a7f22eeccf536d849de569fbf91d..65fa85185ef869ce83bfa1ad020f37238c36ab40 100644 (file)
@@ -215,12 +215,6 @@ ZEND_API int zend_cleanup_class_data(zend_class_entry **pce TSRMLS_DC)
 void _destroy_zend_class_traits_info(zend_class_entry *ce)
 {
        if (ce->num_traits > 0 && ce->traits) {
-               size_t i;
-               for (i = 0; i < ce->num_traits; i++) {
-                       if (ce->traits[i]) {
-                               destroy_zend_class(&ce->traits[i]);
-                       }
-               }
                efree(ce->traits);
        }
        
@@ -267,15 +261,6 @@ void _destroy_zend_class_traits_info(zend_class_entry *ce)
        }
 }
 
-static int zend_clear_trait_method_name(zend_op_array *op_array TSRMLS_DC)
-{
-       if (op_array->function_name && (op_array->fn_flags & ZEND_ACC_ALIAS) == 0) {
-               efree(op_array->function_name);
-               op_array->function_name = NULL;
-       }
-       return 0;
-}
-
 ZEND_API void destroy_zend_class(zend_class_entry **pce)
 {
        zend_class_entry *ce = *pce;
@@ -307,10 +292,6 @@ ZEND_API void destroy_zend_class(zend_class_entry **pce)
                        }
                        zend_hash_destroy(&ce->properties_info);
                        str_efree(ce->name);
-                       if ((ce->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {
-                               TSRMLS_FETCH();
-                               zend_hash_apply(&ce->function_table, (apply_func_t)zend_clear_trait_method_name TSRMLS_CC);
-                       }
                        zend_hash_destroy(&ce->function_table);
                        zend_hash_destroy(&ce->constants_table);
                        if (ce->num_interfaces > 0 && ce->interfaces) {
@@ -400,7 +381,7 @@ ZEND_API void destroy_op_array(zend_op_array *op_array TSRMLS_DC)
        }
        efree(op_array->opcodes);
 
-       if (op_array->function_name && (op_array->fn_flags & ZEND_ACC_ALIAS) == 0) {
+       if (op_array->function_name) {
                efree((char*)op_array->function_name);
        }
        if (op_array->doc_comment) {