]> granicus.if.org Git - php/commitdiff
Split inheritance into separate file
authorNikita Popov <nikic@php.net>
Thu, 18 Sep 2014 22:01:05 +0000 (00:01 +0200)
committerNikita Popov <nikic@php.net>
Fri, 19 Sep 2014 17:54:37 +0000 (19:54 +0200)
This moves handling of inheritance and interface implementation
from zend_compile.c into a separate zend_inheritance.c file, as
this is not really related to compilation.

Zend/Zend.dsp
Zend/ZendTS.dsp
Zend/zend_API.c
Zend/zend_compile.c
Zend/zend_compile.h
Zend/zend_execute.c
Zend/zend_inheritance.c [new file with mode: 0644]
Zend/zend_inheritance.h [new file with mode: 0644]
configure.in

index 98d368fb1617e33ed4f551c02c7cebaa0fe9ba24..c1b3f2a9f7f462f8552577f7cdf2032b9ff8b769 100644 (file)
@@ -179,6 +179,10 @@ SOURCE=.\zend_indent.c
 # End Source File\r
 # Begin Source File\r
 \r
+SOURCE=.\zend_inheritance.c\r
+# End Source File\r
+# Begin Source File\r
+\r
 SOURCE=.\zend_ini.c\r
 # End Source File\r
 # Begin Source File\r
index 21210f10877fbfebfd98e9d4fd2e4083a9436843..4c6ef924652a23554f9e0eecca8737681eb7d09f 100644 (file)
@@ -205,6 +205,10 @@ SOURCE=.\zend_indent.c
 # End Source File\r
 # Begin Source File\r
 \r
+SOURCE=.\zend_inheritance.c\r
+# End Source File\r
+# Begin Source File\r
+\r
 SOURCE=.\zend_ini.c\r
 # End Source File\r
 # Begin Source File\r
index 981e42e41fc2815ada4fd8e1b1babde70266cf09..41adbeba8ffc4a43bdd844ebe70e2395e710dfaf 100644 (file)
@@ -27,6 +27,7 @@
 #include "zend_constants.h"
 #include "zend_exceptions.h"
 #include "zend_closures.h"
+#include "zend_inheritance.h"
 
 #ifdef HAVE_STDARG_H
 #include <stdarg.h>
index 4205a942e01a3349520c3890864d2582c19dcf0e..9cb6f0609e7daefcb9cb39c95ae0c4d8cf357513 100644 (file)
@@ -30,6 +30,7 @@
 #include "zend_virtual_cwd.h"
 #include "zend_multibyte.h"
 #include "zend_language_scanner.h"
+#include "zend_inheritance.h"
 
 #define CONSTANT_EX(op_array, op) \
        (op_array)->literals[op]
@@ -76,29 +77,6 @@ ZEND_API zend_compiler_globals compiler_globals;
 ZEND_API zend_executor_globals executor_globals;
 #endif
 
-static zend_property_info *zend_duplicate_property_info(zend_property_info *property_info TSRMLS_DC) /* {{{ */
-{
-       zend_property_info* new_property_info;
-       
-       new_property_info = zend_arena_alloc(&CG(arena), sizeof(zend_property_info));
-       memcpy(new_property_info, property_info, sizeof(zend_property_info));
-       zend_string_addref(new_property_info->name);
-       if (new_property_info->doc_comment) {
-               zend_string_addref(new_property_info->doc_comment);
-       }
-       return new_property_info;
-}
-/* }}} */
-
-static zend_property_info *zend_duplicate_property_info_internal(zend_property_info *property_info) /* {{{ */
-{
-       zend_property_info* new_property_info = pemalloc(sizeof(zend_property_info), 1);
-       memcpy(new_property_info, property_info, sizeof(zend_property_info));
-       zend_string_addref(new_property_info->name);
-       return new_property_info;
-}
-/* }}} */
-
 static void zend_destroy_property_info(zval *zv) /* {{{ */
 {
        zend_property_info *property_info = Z_PTR_P(zv);
@@ -932,1527 +910,6 @@ ZEND_API void function_add_ref(zend_function *function) /* {{{ */
 }
 /* }}} */
 
-static void do_inherit_parent_constructor(zend_class_entry *ce TSRMLS_DC) /* {{{ */
-{
-       zend_function *function, *new_function;
-
-       if (!ce->parent) {
-               return;
-       }
-
-       /* You cannot change create_object */
-       ce->create_object = ce->parent->create_object;
-
-       /* Inherit special functions if needed */
-       if (!ce->get_iterator) {
-               ce->get_iterator = ce->parent->get_iterator;
-       }
-       if (!ce->iterator_funcs.funcs) {
-               ce->iterator_funcs.funcs = ce->parent->iterator_funcs.funcs;
-       }
-       if (!ce->__get) {
-               ce->__get   = ce->parent->__get;
-       }
-       if (!ce->__set) {
-               ce->__set = ce->parent->__set;
-       }
-       if (!ce->__unset) {
-               ce->__unset = ce->parent->__unset;
-       }
-       if (!ce->__isset) {
-               ce->__isset = ce->parent->__isset;
-       }
-       if (!ce->__call) {
-               ce->__call = ce->parent->__call;
-       }
-       if (!ce->__callstatic) {
-               ce->__callstatic = ce->parent->__callstatic;
-       }
-       if (!ce->__tostring) {
-               ce->__tostring = ce->parent->__tostring;
-       }
-       if (!ce->clone) {
-               ce->clone = ce->parent->clone;
-       }
-       if(!ce->serialize) {
-               ce->serialize = ce->parent->serialize;
-       }
-       if(!ce->unserialize) {
-               ce->unserialize = ce->parent->unserialize;
-       }
-       if (!ce->destructor) {
-               ce->destructor   = ce->parent->destructor;
-       }
-       if (!ce->__debugInfo) {
-               ce->__debugInfo = ce->parent->__debugInfo;
-       }
-       if (ce->constructor) {
-               if (ce->parent->constructor && ce->parent->constructor->common.fn_flags & ZEND_ACC_FINAL) {
-                       zend_error(E_ERROR, "Cannot override final %s::%s() with %s::%s()",
-                               ce->parent->name->val, ce->parent->constructor->common.function_name->val,
-                               ce->name->val, ce->constructor->common.function_name->val
-                               );
-               }
-               return;
-       }
-
-       if ((function = zend_hash_str_find_ptr(&ce->parent->function_table, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1)) != NULL) {
-               /* inherit parent's constructor */
-               if (function->type == ZEND_INTERNAL_FUNCTION) {
-                       new_function = pemalloc(sizeof(zend_internal_function), 1);
-                       memcpy(new_function, function, sizeof(zend_internal_function));
-               } else {
-                       new_function = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
-                       memcpy(new_function, function, sizeof(zend_op_array));
-               }
-               zend_hash_str_update_ptr(&ce->function_table, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1, new_function);
-               function_add_ref(new_function);
-       } else {
-               /* Don't inherit the old style constructor if we already have the new style constructor */
-               zend_string *lc_class_name;
-               zend_string *lc_parent_class_name;
-
-               lc_class_name = zend_string_alloc(ce->name->len, 0);
-               zend_str_tolower_copy(lc_class_name->val, ce->name->val, ce->name->len);
-               if (!zend_hash_exists(&ce->function_table, lc_class_name)) {
-                       lc_parent_class_name = zend_string_alloc(ce->parent->name->len, 0);
-                       zend_str_tolower_copy(lc_parent_class_name->val, ce->parent->name->val, ce->parent->name->len);
-                       if (!zend_hash_exists(&ce->function_table, lc_parent_class_name) &&
-                                       (function = zend_hash_find_ptr(&ce->parent->function_table, lc_parent_class_name)) != NULL) {
-                               if (function->common.fn_flags & ZEND_ACC_CTOR) {
-                                       /* inherit parent's constructor */
-                                       new_function = pemalloc(sizeof(zend_function), function->type == ZEND_INTERNAL_FUNCTION);
-                                       memcpy(new_function, function, sizeof(zend_function));
-                                       zend_hash_update_ptr(&ce->function_table, lc_parent_class_name, new_function);
-                                       function_add_ref(new_function);
-                               }
-                       }
-                       zend_string_release(lc_parent_class_name);
-               }
-               zend_string_free(lc_class_name);
-       }
-       ce->constructor = ce->parent->constructor;
-}
-/* }}} */
-
-char *zend_visibility_string(uint32_t fn_flags) /* {{{ */
-{
-       if (fn_flags & ZEND_ACC_PRIVATE) {
-               return "private";
-       }
-       if (fn_flags & ZEND_ACC_PROTECTED) {
-               return "protected";
-       }
-       if (fn_flags & ZEND_ACC_PUBLIC) {
-               return "public";
-       }
-       return "";
-}
-/* }}} */
-
-static zend_function *do_inherit_method(zend_function *old_function TSRMLS_DC) /* {{{ */
-{
-       zend_function *new_function;
-
-       if (old_function->type == ZEND_INTERNAL_FUNCTION) {
-               new_function = pemalloc(sizeof(zend_internal_function), 1);
-               memcpy(new_function, old_function, sizeof(zend_internal_function));
-       } else {
-               new_function = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
-               memcpy(new_function, old_function, sizeof(zend_op_array));
-       }
-       /* The class entry of the derived function intentionally remains the same
-        * as that of the parent class.  That allows us to know in which context
-        * we're running, and handle private method calls properly.
-        */
-       function_add_ref(new_function);
-       return new_function;
-}
-/* }}} */
-
-static zend_bool zend_do_perform_implementation_check(const zend_function *fe, const zend_function *proto TSRMLS_DC) /* {{{ */
-{
-       uint32_t i, num_args;
-
-       /* If it's a user function then arg_info == NULL means we don't have any parameters but
-        * we still need to do the arg number checks.  We are only willing to ignore this for internal
-        * functions because extensions don't always define arg_info.
-        */
-       if (!proto || (!proto->common.arg_info && proto->common.type != ZEND_USER_FUNCTION)) {
-               return 1;
-       }
-
-       /* Checks for constructors only if they are declared in an interface,
-        * or explicitly marked as abstract
-        */
-       if ((fe->common.fn_flags & ZEND_ACC_CTOR)
-               && ((proto->common.scope->ce_flags & ZEND_ACC_INTERFACE) == 0
-                       && (proto->common.fn_flags & ZEND_ACC_ABSTRACT) == 0)) {
-               return 1;
-       }
-
-       /* If both methods are private do not enforce a signature */
-    if ((fe->common.fn_flags & ZEND_ACC_PRIVATE) && (proto->common.fn_flags & ZEND_ACC_PRIVATE)) {
-               return 1;
-       }
-
-       /* check number of arguments */
-       if (proto->common.required_num_args < fe->common.required_num_args
-               || proto->common.num_args > fe->common.num_args) {
-               return 0;
-       }
-
-       /* by-ref constraints on return values are covariant */
-       if ((proto->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)
-               && !(fe->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)) {
-               return 0;
-       }
-
-       if ((proto->common.fn_flags & ZEND_ACC_VARIADIC)
-               && !(fe->common.fn_flags & ZEND_ACC_VARIADIC)) {
-               return 0;
-       }
-
-       /* For variadic functions any additional (optional) arguments that were added must be
-        * checked against the signature of the variadic argument, so in this case we have to
-        * go through all the parameters of the function and not just those present in the
-        * prototype. */
-       num_args = proto->common.num_args;
-       if ((proto->common.fn_flags & ZEND_ACC_VARIADIC)
-               && fe->common.num_args > proto->common.num_args) {
-               num_args = fe->common.num_args;
-       }
-
-       for (i = 0; i < num_args; i++) {
-               zend_arg_info *fe_arg_info = &fe->common.arg_info[i];
-
-               zend_arg_info *proto_arg_info;
-               if (i < proto->common.num_args) {
-                       proto_arg_info = &proto->common.arg_info[i];
-               } else {
-                       proto_arg_info = &proto->common.arg_info[proto->common.num_args-1];
-               }
-
-               if (ZEND_LOG_XOR(fe_arg_info->class_name, proto_arg_info->class_name)) {
-                       /* Only one has a type hint and the other one doesn't */
-                       return 0;
-               }
-
-               if (fe_arg_info->class_name) {
-                       zend_string *fe_class_name, *proto_class_name;
-
-                       if (!strcasecmp(fe_arg_info->class_name, "parent") && proto->common.scope) {
-                               fe_class_name = zend_string_copy(proto->common.scope->name);
-                       } else if (!strcasecmp(fe_arg_info->class_name, "self") && fe->common.scope) {
-                               fe_class_name = zend_string_copy(fe->common.scope->name);
-                       } else {
-                               fe_class_name = zend_string_init(
-                                       fe_arg_info->class_name,
-                                       fe_arg_info->class_name_len, 0);
-                       }
-
-                       if (!strcasecmp(proto_arg_info->class_name, "parent") && proto->common.scope && proto->common.scope->parent) {
-                               proto_class_name = zend_string_copy(proto->common.scope->parent->name);
-                       } else if (!strcasecmp(proto_arg_info->class_name, "self") && proto->common.scope) {
-                               proto_class_name = zend_string_copy(proto->common.scope->name);
-                       } else {
-                               proto_class_name = zend_string_init(
-                                       proto_arg_info->class_name,
-                                       proto_arg_info->class_name_len, 0);
-                       }
-
-                       if (strcasecmp(fe_class_name->val, proto_class_name->val)!=0) {
-                               const char *colon;
-
-                               if (fe->common.type != ZEND_USER_FUNCTION) {
-                                       zend_string_release(proto_class_name);
-                                       zend_string_release(fe_class_name);
-                                       return 0;
-                           } else if (strchr(proto_class_name->val, '\\') != NULL ||
-                                               (colon = zend_memrchr(fe_class_name->val, '\\', fe_class_name->len)) == NULL ||
-                                               strcasecmp(colon+1, proto_class_name->val) != 0) {
-                                       zend_class_entry *fe_ce, *proto_ce;
-
-                                       fe_ce = zend_lookup_class(fe_class_name TSRMLS_CC);
-                                       proto_ce = zend_lookup_class(proto_class_name TSRMLS_CC);
-
-                                       /* Check for class alias */
-                                       if (!fe_ce || !proto_ce ||
-                                                       fe_ce->type == ZEND_INTERNAL_CLASS ||
-                                                       proto_ce->type == ZEND_INTERNAL_CLASS ||
-                                                       fe_ce != proto_ce) {
-                                               zend_string_release(proto_class_name);
-                                               zend_string_release(fe_class_name);
-                                               return 0;
-                                       }
-                               }
-                       }
-                       zend_string_release(proto_class_name);
-                       zend_string_release(fe_class_name);
-               }
-               if (fe_arg_info->type_hint != proto_arg_info->type_hint) {
-                       /* Incompatible type hint */
-                       return 0;
-               }
-
-               /* by-ref constraints on arguments are invariant */
-               if (fe_arg_info->pass_by_reference != proto_arg_info->pass_by_reference) {
-                       return 0;
-               }
-       }
-
-       return 1;
-}
-/* }}} */
-
-#define REALLOC_BUF_IF_EXCEED(buf, offset, length, size) \
-       if (UNEXPECTED(offset - buf + size >= length)) {        \
-               length += size + 1;                             \
-               buf = erealloc(buf, length);            \
-       }
-
-static char *zend_get_function_declaration(zend_function *fptr TSRMLS_DC) /* {{{ */
-{
-       char *offset, *buf;
-       uint32_t length = 1024;
-
-       offset = buf = (char *)emalloc(length * sizeof(char));
-       if (fptr->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) {
-               *(offset++) = '&';
-               *(offset++) = ' ';
-       }
-
-       if (fptr->common.scope) {
-               memcpy(offset, fptr->common.scope->name->val, fptr->common.scope->name->len);
-               offset += fptr->common.scope->name->len;
-               *(offset++) = ':';
-               *(offset++) = ':';
-       }
-
-       {
-               size_t name_len = fptr->common.function_name->len;
-               REALLOC_BUF_IF_EXCEED(buf, offset, length, name_len);
-               memcpy(offset, fptr->common.function_name->val, name_len);
-               offset += name_len;
-       }
-
-       *(offset++) = '(';
-       if (fptr->common.arg_info) {
-               uint32_t i, required;
-               zend_arg_info *arg_info = fptr->common.arg_info;
-
-               required = fptr->common.required_num_args;
-               for (i = 0; i < fptr->common.num_args;) {
-                       if (arg_info->class_name) {
-                               const char *class_name;
-                               uint32_t class_name_len;
-                               if (!strcasecmp(arg_info->class_name, "self") && fptr->common.scope ) {
-                                       class_name = fptr->common.scope->name->val;
-                                       class_name_len = fptr->common.scope->name->len;
-                               } else if (!strcasecmp(arg_info->class_name, "parent") && fptr->common.scope->parent) {
-                                       class_name = fptr->common.scope->parent->name->val;
-                                       class_name_len = fptr->common.scope->parent->name->len;
-                               } else {
-                                       class_name = arg_info->class_name;
-                                       class_name_len = arg_info->class_name_len;
-                               }
-                               REALLOC_BUF_IF_EXCEED(buf, offset, length, class_name_len);
-                               memcpy(offset, class_name, class_name_len);
-                               offset += class_name_len;
-                               *(offset++) = ' ';
-                       } else if (arg_info->type_hint) {
-                               uint32_t type_name_len;
-                               char *type_name = zend_get_type_by_const(arg_info->type_hint);
-                               type_name_len = strlen(type_name);
-                               REALLOC_BUF_IF_EXCEED(buf, offset, length, type_name_len);
-                               memcpy(offset, type_name, type_name_len);
-                               offset += type_name_len;
-                               *(offset++) = ' ';
-                       }
-
-                       if (arg_info->pass_by_reference) {
-                               *(offset++) = '&';
-                       }
-
-                       if (arg_info->is_variadic) {
-                               *(offset++) = '.';
-                               *(offset++) = '.';
-                               *(offset++) = '.';
-                       }
-
-                       *(offset++) = '$';
-
-                       if (arg_info->name) {
-                               REALLOC_BUF_IF_EXCEED(buf, offset, length, arg_info->name_len);
-                               memcpy(offset, arg_info->name, arg_info->name_len);
-                               offset += arg_info->name_len;
-                       } else {
-                               uint32_t idx = i;
-                               memcpy(offset, "param", 5);
-                               offset += 5;
-                               do {
-                                       *(offset++) = (char) (idx % 10) + '0';
-                                       idx /= 10;
-                               } while (idx > 0);
-                       }
-                       if (i >= required && !arg_info->is_variadic) {
-                               *(offset++) = ' ';
-                               *(offset++) = '=';
-                               *(offset++) = ' ';
-                               if (fptr->type == ZEND_USER_FUNCTION) {
-                                       zend_op *precv = NULL;
-                                       {
-                                               uint32_t idx  = i;
-                                               zend_op *op = ((zend_op_array *)fptr)->opcodes;
-                                               zend_op *end = op + ((zend_op_array *)fptr)->last;
-
-                                               ++idx;
-                                               while (op < end) {
-                                                       if ((op->opcode == ZEND_RECV || op->opcode == ZEND_RECV_INIT)
-                                                                       && op->op1.num == (zend_ulong)idx)
-                                                       {
-                                                               precv = op;
-                                                       }
-                                                       ++op;
-                                               }
-                                       }
-                                       if (precv && precv->opcode == ZEND_RECV_INIT && precv->op2_type != IS_UNUSED) {
-                                               zval *zv = precv->op2.zv;
-
-                                               if (Z_TYPE_P(zv) == IS_CONSTANT) {
-                                                       REALLOC_BUF_IF_EXCEED(buf, offset, length, Z_STRLEN_P(zv));
-                                                       memcpy(offset, Z_STRVAL_P(zv), Z_STRLEN_P(zv));
-                                                       offset += Z_STRLEN_P(zv);
-                                               } else if (Z_TYPE_P(zv) == IS_FALSE) {
-                                                       memcpy(offset, "false", 5);
-                                                       offset += 5;
-                                               } else if (Z_TYPE_P(zv) == IS_TRUE) {
-                                                       memcpy(offset, "true", 4);
-                                                       offset += 4;
-                                               } else if (Z_TYPE_P(zv) == IS_NULL) {
-                                                       memcpy(offset, "NULL", 4);
-                                                       offset += 4;
-                                               } else if (Z_TYPE_P(zv) == IS_STRING) {
-                                                       *(offset++) = '\'';
-                                                       REALLOC_BUF_IF_EXCEED(buf, offset, length, MIN(Z_STRLEN_P(zv), 10));
-                                                       memcpy(offset, Z_STRVAL_P(zv), MIN(Z_STRLEN_P(zv), 10));
-                                                       offset += MIN(Z_STRLEN_P(zv), 10);
-                                                       if (Z_STRLEN_P(zv) > 10) {
-                                                               *(offset++) = '.';
-                                                               *(offset++) = '.';
-                                                               *(offset++) = '.';
-                                                       }
-                                                       *(offset++) = '\'';
-                                               } else if (Z_TYPE_P(zv) == IS_ARRAY) {
-                                                       memcpy(offset, "Array", 5);
-                                                       offset += 5;
-                                               } else if (Z_TYPE_P(zv) == IS_CONSTANT_AST) {
-                                                       memcpy(offset, "<expression>", 12);
-                                                       offset += 12;
-                                               } else {
-                                                       zend_string *str = zval_get_string(zv);
-                                                       REALLOC_BUF_IF_EXCEED(buf, offset, length, str->len);
-                                                       memcpy(offset, str->val, str->len);
-                                                       offset += str->len;
-                                                       zend_string_release(str);
-                                               }
-                                       }
-                               } else {
-                                       memcpy(offset, "NULL", 4);
-                                       offset += 4;
-                               }
-                       }
-
-                       if (++i < fptr->common.num_args) {
-                               *(offset++) = ',';
-                               *(offset++) = ' ';
-                       }
-                       arg_info++;
-                       REALLOC_BUF_IF_EXCEED(buf, offset, length, 32);
-               }
-       }
-       *(offset++) = ')';
-       *offset = '\0';
-
-       return buf;
-}
-/* }}} */
-
-static void do_inheritance_check_on_method(zend_function *child, zend_function *parent TSRMLS_DC) /* {{{ */
-{
-       uint32_t child_flags;
-       uint32_t parent_flags = parent->common.fn_flags;
-
-       if ((parent->common.scope->ce_flags & ZEND_ACC_INTERFACE) == 0
-               && parent->common.fn_flags & ZEND_ACC_ABSTRACT
-               && parent->common.scope != (child->common.prototype ? child->common.prototype->common.scope : child->common.scope)
-               && child->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_IMPLEMENTED_ABSTRACT)) {
-               zend_error_noreturn(E_COMPILE_ERROR, "Can't inherit abstract function %s::%s() (previously declared abstract in %s)",
-                       parent->common.scope->name->val,
-                       child->common.function_name->val,
-                       child->common.prototype ? child->common.prototype->common.scope->name->val : child->common.scope->name->val);
-       }
-
-       if (parent_flags & ZEND_ACC_FINAL) {
-               zend_error_noreturn(E_COMPILE_ERROR, "Cannot override final method %s::%s()", ZEND_FN_SCOPE_NAME(parent), child->common.function_name->val);
-       }
-
-       child_flags     = child->common.fn_flags;
-       /* You cannot change from static to non static and vice versa.
-        */
-       if ((child_flags & ZEND_ACC_STATIC) != (parent_flags & ZEND_ACC_STATIC)) {
-               if (child->common.fn_flags & ZEND_ACC_STATIC) {
-                       zend_error_noreturn(E_COMPILE_ERROR, "Cannot make non static method %s::%s() static in class %s", ZEND_FN_SCOPE_NAME(parent), child->common.function_name->val, ZEND_FN_SCOPE_NAME(child));
-               } else {
-                       zend_error_noreturn(E_COMPILE_ERROR, "Cannot make static method %s::%s() non static in class %s", ZEND_FN_SCOPE_NAME(parent), child->common.function_name->val, ZEND_FN_SCOPE_NAME(child));
-               }
-       }
-
-       /* Disallow making an inherited method abstract. */
-       if ((child_flags & ZEND_ACC_ABSTRACT) && !(parent_flags & ZEND_ACC_ABSTRACT)) {
-               zend_error_noreturn(E_COMPILE_ERROR, "Cannot make non abstract method %s::%s() abstract in class %s", ZEND_FN_SCOPE_NAME(parent), child->common.function_name->val, ZEND_FN_SCOPE_NAME(child));
-       }
-
-       if (parent_flags & ZEND_ACC_CHANGED) {
-               child->common.fn_flags |= ZEND_ACC_CHANGED;
-       } else {
-               /* Prevent derived classes from restricting access that was available in parent classes
-                */
-               if ((child_flags & ZEND_ACC_PPP_MASK) > (parent_flags & ZEND_ACC_PPP_MASK)) {
-                       zend_error_noreturn(E_COMPILE_ERROR, "Access level to %s::%s() must be %s (as in class %s)%s", ZEND_FN_SCOPE_NAME(child), child->common.function_name->val, zend_visibility_string(parent_flags), ZEND_FN_SCOPE_NAME(parent), (parent_flags&ZEND_ACC_PUBLIC) ? "" : " or weaker");
-               } else if (((child_flags & ZEND_ACC_PPP_MASK) < (parent_flags & ZEND_ACC_PPP_MASK))
-                       && ((parent_flags & ZEND_ACC_PPP_MASK) & ZEND_ACC_PRIVATE)) {
-                       child->common.fn_flags |= ZEND_ACC_CHANGED;
-               }
-       }
-
-       if (parent_flags & ZEND_ACC_PRIVATE) {
-               child->common.prototype = NULL;
-       } else if (parent_flags & ZEND_ACC_ABSTRACT) {
-               child->common.fn_flags |= ZEND_ACC_IMPLEMENTED_ABSTRACT;
-               child->common.prototype = parent;
-       } else if (!(parent->common.fn_flags & ZEND_ACC_CTOR) || (parent->common.prototype && (parent->common.prototype->common.scope->ce_flags & ZEND_ACC_INTERFACE))) {
-               /* ctors only have a prototype if it comes from an interface */
-               child->common.prototype = parent->common.prototype ? parent->common.prototype : parent;
-       }
-
-       if (child->common.prototype && (child->common.prototype->common.fn_flags & ZEND_ACC_ABSTRACT)) {
-               if (!zend_do_perform_implementation_check(child, child->common.prototype TSRMLS_CC)) {
-                       zend_error_noreturn(E_COMPILE_ERROR, "Declaration of %s::%s() must be compatible with %s", ZEND_FN_SCOPE_NAME(child), child->common.function_name->val, zend_get_function_declaration(child->common.prototype TSRMLS_CC));
-               }
-       } else if (EG(error_reporting) & E_STRICT || Z_TYPE(EG(user_error_handler)) != IS_UNDEF) { /* Check E_STRICT (or custom error handler) before the check so that we save some time */
-               if (!zend_do_perform_implementation_check(child, parent TSRMLS_CC)) {
-                       char *method_prototype = zend_get_function_declaration(parent TSRMLS_CC);
-                       zend_error(E_STRICT, "Declaration of %s::%s() should be compatible with %s", ZEND_FN_SCOPE_NAME(child), child->common.function_name->val, method_prototype);
-                       efree(method_prototype);
-               }
-       }
-}
-/* }}} */
-
-static zend_bool do_inherit_method_check(HashTable *child_function_table, zend_function *parent, zend_string *key, zend_class_entry *child_ce) /* {{{ */
-{
-       uint32_t parent_flags = parent->common.fn_flags;
-       zend_function *child;
-       TSRMLS_FETCH();
-
-       if ((child = zend_hash_find_ptr(child_function_table, key)) == NULL) {
-               if (parent_flags & (ZEND_ACC_ABSTRACT)) {
-                       child_ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
-               }
-               return 1; /* method doesn't exist in child, copy from parent */
-       }
-
-       do_inheritance_check_on_method(child, parent TSRMLS_CC);
-
-       return 0;
-}
-/* }}} */
-
-static zend_bool do_inherit_property_access_check(HashTable *target_ht, zend_property_info *parent_info, zend_string *key, zend_class_entry *ce TSRMLS_DC) /* {{{ */
-{
-       zend_property_info *child_info;
-       zend_class_entry *parent_ce = ce->parent;
-
-       if (parent_info->flags & (ZEND_ACC_PRIVATE|ZEND_ACC_SHADOW)) {
-               if ((child_info = zend_hash_find_ptr(&ce->properties_info, key)) != NULL) {
-                       child_info->flags |= ZEND_ACC_CHANGED;
-               } else {
-                       if(ce->type & ZEND_INTERNAL_CLASS) {
-                               child_info = zend_duplicate_property_info_internal(parent_info);
-                       } else {
-                               child_info = zend_duplicate_property_info(parent_info TSRMLS_CC);
-                       }
-                       zend_hash_update_ptr(&ce->properties_info, key, child_info);
-                       child_info->flags &= ~ZEND_ACC_PRIVATE; /* it's not private anymore */
-                       child_info->flags |= ZEND_ACC_SHADOW; /* but it's a shadow of private */
-               }
-               return 0; /* don't copy access information to child */
-       }
-
-       if ((child_info = zend_hash_find_ptr(&ce->properties_info, key)) != NULL) {
-               if ((parent_info->flags & ZEND_ACC_STATIC) != (child_info->flags & ZEND_ACC_STATIC)) {
-                       zend_error_noreturn(E_COMPILE_ERROR, "Cannot redeclare %s%s::$%s as %s%s::$%s",
-                               (parent_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", parent_ce->name->val, key->val,
-                               (child_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", ce->name->val, key->val);
-
-               }
-
-               if(parent_info->flags & ZEND_ACC_CHANGED) {
-                       child_info->flags |= ZEND_ACC_CHANGED;
-               }
-
-               if ((child_info->flags & ZEND_ACC_PPP_MASK) > (parent_info->flags & ZEND_ACC_PPP_MASK)) {
-                       zend_error_noreturn(E_COMPILE_ERROR, "Access level to %s::$%s must be %s (as in class %s)%s", ce->name->val, key->val, zend_visibility_string(parent_info->flags), parent_ce->name->val, (parent_info->flags&ZEND_ACC_PUBLIC) ? "" : " or weaker");
-               } else if ((child_info->flags & ZEND_ACC_STATIC) == 0) {
-                       zval_ptr_dtor(&(ce->default_properties_table[parent_info->offset]));
-                       ce->default_properties_table[parent_info->offset] = ce->default_properties_table[child_info->offset];
-                       ZVAL_UNDEF(&ce->default_properties_table[child_info->offset]);
-                       child_info->offset = parent_info->offset;
-               }
-               return 0;       /* Don't copy from parent */
-       } else {
-               return 1;       /* Copy from parent */
-       }
-}
-/* }}} */
-
-static inline void do_implement_interface(zend_class_entry *ce, zend_class_entry *iface TSRMLS_DC) /* {{{ */
-{
-       if (!(ce->ce_flags & ZEND_ACC_INTERFACE) && iface->interface_gets_implemented && iface->interface_gets_implemented(iface, ce TSRMLS_CC) == FAILURE) {
-               zend_error(E_CORE_ERROR, "Class %s could not implement interface %s", ce->name->val, iface->name->val);
-       }
-       if (ce == iface) {
-               zend_error(E_ERROR, "Interface %s cannot implement itself", ce->name->val);
-       }
-}
-/* }}} */
-
-ZEND_API void zend_do_inherit_interfaces(zend_class_entry *ce, const zend_class_entry *iface TSRMLS_DC) /* {{{ */
-{
-       /* expects interface to be contained in ce's interface list already */
-       uint32_t i, ce_num, if_num = iface->num_interfaces;
-       zend_class_entry *entry;
-
-       if (if_num==0) {
-               return;
-       }
-       ce_num = ce->num_interfaces;
-
-       if (ce->type == ZEND_INTERNAL_CLASS) {
-               ce->interfaces = (zend_class_entry **) realloc(ce->interfaces, sizeof(zend_class_entry *) * (ce_num + if_num));
-       } else {
-               ce->interfaces = (zend_class_entry **) erealloc(ce->interfaces, sizeof(zend_class_entry *) * (ce_num + if_num));
-       }
-
-       /* Inherit the interfaces, only if they're not already inherited by the class */
-       while (if_num--) {
-               entry = iface->interfaces[if_num];
-               for (i = 0; i < ce_num; i++) {
-                       if (ce->interfaces[i] == entry) {
-                               break;
-                       }
-               }
-               if (i == ce_num) {
-                       ce->interfaces[ce->num_interfaces++] = entry;
-               }
-       }
-
-       /* and now call the implementing handlers */
-       while (ce_num < ce->num_interfaces) {
-               do_implement_interface(ce, ce->interfaces[ce_num++] TSRMLS_CC);
-       }
-}
-/* }}} */
-
-#ifdef ZTS
-# define zval_property_ctor(parent_ce, ce) \
-       (((parent_ce)->type != (ce)->type) ? ZVAL_COPY_CTOR : zval_add_ref)
-#else
-# define zval_property_ctor(parent_ce, ce) \
-       zval_add_ref
-#endif
-
-static void do_inherit_class_constant(zend_string *name, zval *zv, zend_class_entry *ce, zend_class_entry *parent_ce TSRMLS_DC) /* {{{ */
-{
-       if (!Z_ISREF_P(zv)) {
-               if (parent_ce->type == ZEND_INTERNAL_CLASS) {
-                       ZVAL_NEW_PERSISTENT_REF(zv, zv);
-               } else {
-                       ZVAL_NEW_REF(zv, zv);
-               }
-       }
-       if (Z_CONSTANT_P(Z_REFVAL_P(zv))) {
-               ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
-       }
-       if (zend_hash_add(&ce->constants_table, name, zv)) {
-               Z_ADDREF_P(zv);
-       }
-}
-/* }}} */
-
-ZEND_API void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent_ce TSRMLS_DC) /* {{{ */
-{
-       zend_property_info *property_info;
-       zend_function *func;
-       zend_string *key;
-       zval *zv;
-
-       if ((ce->ce_flags & ZEND_ACC_INTERFACE)
-               && !(parent_ce->ce_flags & ZEND_ACC_INTERFACE)) {
-               zend_error_noreturn(E_COMPILE_ERROR, "Interface %s may not inherit from class (%s)", ce->name->val, parent_ce->name->val);
-       }
-       if (parent_ce->ce_flags & ZEND_ACC_FINAL_CLASS) {
-               zend_error_noreturn(E_COMPILE_ERROR, "Class %s may not inherit from final class (%s)", ce->name->val, parent_ce->name->val);
-       }
-
-       ce->parent = parent_ce;
-       /* Copy serialize/unserialize callbacks */
-       if (!ce->serialize) {
-               ce->serialize   = parent_ce->serialize;
-       }
-       if (!ce->unserialize) {
-               ce->unserialize = parent_ce->unserialize;
-       }
-
-       /* Inherit interfaces */
-       zend_do_inherit_interfaces(ce, parent_ce TSRMLS_CC);
-
-       /* Inherit properties */
-       if (parent_ce->default_properties_count) {
-               int i = ce->default_properties_count + parent_ce->default_properties_count;
-
-               ce->default_properties_table = perealloc(ce->default_properties_table, sizeof(zval) * i, ce->type == ZEND_INTERNAL_CLASS);
-               if (ce->default_properties_count) {
-                       while (i-- > parent_ce->default_properties_count) {
-                               ce->default_properties_table[i] = ce->default_properties_table[i - parent_ce->default_properties_count];
-                       }
-               }
-               for (i = 0; i < parent_ce->default_properties_count; i++) {
-#ifdef ZTS
-                       if (parent_ce->type != ce->type) {
-                               ZVAL_DUP(&ce->default_properties_table[i], &parent_ce->default_properties_table[i]);
-                               if (Z_OPT_CONSTANT(ce->default_properties_table[i])) {
-                                       ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
-                               }
-                               continue;
-                       }
-#endif
-
-                       ZVAL_COPY(&ce->default_properties_table[i], &parent_ce->default_properties_table[i]);
-                       if (Z_OPT_CONSTANT(ce->default_properties_table[i])) {
-                               ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
-                       }
-               }
-               ce->default_properties_count += parent_ce->default_properties_count;
-       }
-
-       if (parent_ce->type != ce->type) {
-               /* User class extends internal class */
-               zend_update_class_constants(parent_ce  TSRMLS_CC);
-               if (parent_ce->default_static_members_count) {
-                       int i = ce->default_static_members_count + parent_ce->default_static_members_count;
-
-                       ce->default_static_members_table = erealloc(ce->default_static_members_table, sizeof(zval) * i);
-                       if (ce->default_static_members_count) {
-                               while (i-- > parent_ce->default_static_members_count) {
-                                       ce->default_static_members_table[i] = ce->default_static_members_table[i - parent_ce->default_static_members_count];
-                               }
-                       }
-                       for (i = 0; i < parent_ce->default_static_members_count; i++) {
-                               ZVAL_MAKE_REF(&CE_STATIC_MEMBERS(parent_ce)[i]);
-                               ce->default_static_members_table[i] = CE_STATIC_MEMBERS(parent_ce)[i];
-                               Z_ADDREF(ce->default_static_members_table[i]);
-                               if (Z_CONSTANT_P(Z_REFVAL(ce->default_static_members_table[i]))) {
-                                       ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
-                               }
-                       }
-                       ce->default_static_members_count += parent_ce->default_static_members_count;
-                       ce->static_members_table = ce->default_static_members_table;
-               }
-       } else {
-               if (parent_ce->default_static_members_count) {
-                       int i = ce->default_static_members_count + parent_ce->default_static_members_count;
-
-                       ce->default_static_members_table = perealloc(ce->default_static_members_table, sizeof(zval) * i, ce->type == ZEND_INTERNAL_CLASS);
-                       if (ce->default_static_members_count) {
-                               while (i-- > parent_ce->default_static_members_count) {
-                                       ce->default_static_members_table[i] = ce->default_static_members_table[i - parent_ce->default_static_members_count];
-                               }
-                       }
-                       for (i = 0; i < parent_ce->default_static_members_count; i++) {
-                               ZVAL_MAKE_REF(&parent_ce->default_static_members_table[i]);
-                               ce->default_static_members_table[i] = parent_ce->default_static_members_table[i];
-                               Z_ADDREF(ce->default_static_members_table[i]);
-                               if (Z_CONSTANT_P(Z_REFVAL(ce->default_static_members_table[i]))) {
-                                       ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
-                               }
-                       }
-                       ce->default_static_members_count += parent_ce->default_static_members_count;
-                       if (ce->type == ZEND_USER_CLASS) {
-                               ce->static_members_table = ce->default_static_members_table;
-                       }
-               }
-       }
-
-       ZEND_HASH_FOREACH_PTR(&ce->properties_info, property_info) {
-               if (property_info->ce == ce) {
-                       if (property_info->flags & ZEND_ACC_STATIC) {
-                               property_info->offset += parent_ce->default_static_members_count;
-                       } else {
-                               property_info->offset += parent_ce->default_properties_count;
-                       }
-               }
-       } ZEND_HASH_FOREACH_END();
-
-       ZEND_HASH_FOREACH_STR_KEY_PTR(&parent_ce->properties_info, key, property_info) {
-               if (do_inherit_property_access_check(&ce->properties_info, property_info, key, ce TSRMLS_CC)) {
-                       if (ce->type & ZEND_INTERNAL_CLASS) {
-                               property_info = zend_duplicate_property_info_internal(property_info);
-                       } else {
-                               property_info = zend_duplicate_property_info(property_info TSRMLS_CC);
-                       }
-                       zend_hash_add_new_ptr(&ce->properties_info, key, property_info);
-               }
-       } ZEND_HASH_FOREACH_END();
-
-       ZEND_HASH_FOREACH_STR_KEY_VAL(&parent_ce->constants_table, key, zv) {
-               do_inherit_class_constant(key, zv, ce, parent_ce TSRMLS_CC);
-       } ZEND_HASH_FOREACH_END();
-
-       ZEND_HASH_FOREACH_STR_KEY_PTR(&parent_ce->function_table, key, func) {
-               if (do_inherit_method_check(&ce->function_table, func, key, ce)) {
-                       zend_function *new_func = do_inherit_method(func TSRMLS_CC);
-                       zend_hash_add_new_ptr(&ce->function_table, key, new_func);
-               }
-       } ZEND_HASH_FOREACH_END();
-
-       do_inherit_parent_constructor(ce TSRMLS_CC);
-
-       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|ZEND_ACC_IMPLEMENT_TRAITS))) {
-               /* The verification will be done in runtime by ZEND_VERIFY_ABSTRACT_CLASS */
-               zend_verify_abstract_class(ce TSRMLS_CC);
-       }
-       ce->ce_flags |= parent_ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS;
-}
-/* }}} */
-
-static zend_bool do_inherit_constant_check(HashTable *child_constants_table, zval *parent_constant, zend_string *name, const zend_class_entry *iface) /* {{{ */
-{
-       zval *old_constant;
-
-       if ((old_constant = zend_hash_find(child_constants_table, name)) != NULL) {
-               if (!Z_ISREF_P(old_constant) ||
-                   !Z_ISREF_P(parent_constant) ||
-                   Z_REFVAL_P(old_constant) != Z_REFVAL_P(parent_constant)) {
-                       zend_error_noreturn(E_COMPILE_ERROR, "Cannot inherit previously-inherited or override constant %s from interface %s", name->val, iface->name->val);
-               }
-               return 0;
-       }
-       return 1;
-}
-/* }}} */
-
-static void do_inherit_iface_constant(zend_string *name, zval *zv, zend_class_entry *ce, zend_class_entry *iface TSRMLS_DC) /* {{{ */
-{
-       if (do_inherit_constant_check(&ce->constants_table, zv, name, iface)) {
-               ZVAL_MAKE_REF(zv);
-               Z_ADDREF_P(zv);
-               if (Z_CONSTANT_P(Z_REFVAL_P(zv))) {
-                       ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
-               }
-               zend_hash_update(&ce->constants_table, name, zv);
-       }
-}
-/* }}} */
-
-ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry *iface TSRMLS_DC) /* {{{ */
-{
-       uint32_t i, ignore = 0;
-       uint32_t current_iface_num = ce->num_interfaces;
-       uint32_t parent_iface_num  = ce->parent ? ce->parent->num_interfaces : 0;
-       zend_function *func;
-       zend_string *key;
-       zval *zv;
-
-       for (i = 0; i < ce->num_interfaces; i++) {
-               if (ce->interfaces[i] == NULL) {
-                       memmove(ce->interfaces + i, ce->interfaces + i + 1, sizeof(zend_class_entry*) * (--ce->num_interfaces - i));
-                       i--;
-               } else if (ce->interfaces[i] == iface) {
-                       if (i < parent_iface_num) {
-                               ignore = 1;
-                       } else {
-                               zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot implement previously implemented interface %s", ce->name->val, iface->name->val);
-                       }
-               }
-       }
-       if (ignore) {
-               /* Check for attempt to redeclare interface constants */
-               ZEND_HASH_FOREACH_STR_KEY_VAL(&ce->constants_table, key, zv) {
-                       do_inherit_constant_check(&iface->constants_table, zv, key, iface);
-               } ZEND_HASH_FOREACH_END();
-       } else {
-               if (ce->num_interfaces >= current_iface_num) {
-                       if (ce->type == ZEND_INTERNAL_CLASS) {
-                               ce->interfaces = (zend_class_entry **) realloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num));
-                       } else {
-                               ce->interfaces = (zend_class_entry **) erealloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num));
-                       }
-               }
-               ce->interfaces[ce->num_interfaces++] = iface;
-
-               ZEND_HASH_FOREACH_STR_KEY_VAL(&iface->constants_table, key, zv) {
-                       do_inherit_iface_constant(key, zv, ce, iface TSRMLS_CC);
-               } ZEND_HASH_FOREACH_END();
-
-               ZEND_HASH_FOREACH_STR_KEY_PTR(&iface->function_table, key, func) {
-                       if (do_inherit_method_check(&ce->function_table, func, key, ce)) {
-                               zend_function *new_func = do_inherit_method(func TSRMLS_CC);
-                               zend_hash_add_new_ptr(&ce->function_table, key, new_func);
-                       }
-               } ZEND_HASH_FOREACH_END();
-
-               do_implement_interface(ce, iface TSRMLS_CC);
-               zend_do_inherit_interfaces(ce, iface TSRMLS_CC);
-       }
-}
-/* }}} */
-
-ZEND_API void zend_do_implement_trait(zend_class_entry *ce, zend_class_entry *trait TSRMLS_DC) /* {{{ */
-{
-       uint32_t i, ignore = 0;
-       uint32_t current_trait_num = ce->num_traits;
-       uint32_t parent_trait_num  = ce->parent ? ce->parent->num_traits : 0;
-
-       for (i = 0; i < ce->num_traits; i++) {
-               if (ce->traits[i] == NULL) {
-                       memmove(ce->traits + i, ce->traits + i + 1, sizeof(zend_class_entry*) * (--ce->num_traits - i));
-                       i--;
-               } else if (ce->traits[i] == trait) {
-                       if (i < parent_trait_num) {
-                               ignore = 1;
-                       }
-               }
-       }
-       if (!ignore) {
-               if (ce->num_traits >= current_trait_num) {
-                       if (ce->type == ZEND_INTERNAL_CLASS) {
-                               ce->traits = (zend_class_entry **) realloc(ce->traits, sizeof(zend_class_entry *) * (++current_trait_num));
-                       } else {
-                               ce->traits = (zend_class_entry **) erealloc(ce->traits, sizeof(zend_class_entry *) * (++current_trait_num));
-                       }
-               }
-               ce->traits[ce->num_traits++] = trait;
-       }
-}
-/* }}} */
-
-static zend_bool zend_traits_method_compatibility_check(zend_function *fn, zend_function *other_fn TSRMLS_DC) /* {{{ */
-{
-       uint32_t    fn_flags = fn->common.scope->ce_flags;
-       uint32_t other_flags = other_fn->common.scope->ce_flags;
-
-       return zend_do_perform_implementation_check(fn, other_fn TSRMLS_CC)
-               && ((other_fn->common.scope->ce_flags & ZEND_ACC_INTERFACE) || zend_do_perform_implementation_check(other_fn, fn TSRMLS_CC))
-               && ((fn_flags & (ZEND_ACC_FINAL|ZEND_ACC_STATIC)) ==
-                   (other_flags & (ZEND_ACC_FINAL|ZEND_ACC_STATIC))); /* equal final and static qualifier */
-}
-/* }}} */
-
-static void zend_add_magic_methods(zend_class_entry* ce, zend_string* mname, zend_function* fe TSRMLS_DC) /* {{{ */
-{
-       if (!strncmp(mname->val, ZEND_CLONE_FUNC_NAME, mname->len)) {
-               ce->clone = fe; fe->common.fn_flags |= ZEND_ACC_CLONE;
-       } else if (!strncmp(mname->val, ZEND_CONSTRUCTOR_FUNC_NAME, mname->len)) {
-               if (ce->constructor) {
-                       zend_error_noreturn(E_COMPILE_ERROR, "%s has colliding constructor definitions coming from traits", ce->name->val);
-               }
-               ce->constructor = fe; fe->common.fn_flags |= ZEND_ACC_CTOR;
-       } else if (!strncmp(mname->val, ZEND_DESTRUCTOR_FUNC_NAME,  mname->len)) {
-               ce->destructor = fe; fe->common.fn_flags |= ZEND_ACC_DTOR;
-       } else if (!strncmp(mname->val, ZEND_GET_FUNC_NAME, mname->len)) {
-               ce->__get = fe;
-       } else if (!strncmp(mname->val, ZEND_SET_FUNC_NAME, mname->len)) {
-               ce->__set = fe;
-       } else if (!strncmp(mname->val, ZEND_CALL_FUNC_NAME, mname->len)) {
-               ce->__call = fe;
-       } else if (!strncmp(mname->val, ZEND_UNSET_FUNC_NAME, mname->len)) {
-               ce->__unset = fe;
-       } else if (!strncmp(mname->val, ZEND_ISSET_FUNC_NAME, mname->len)) {
-               ce->__isset = fe;
-       } else if (!strncmp(mname->val, ZEND_CALLSTATIC_FUNC_NAME, mname->len)) {
-               ce->__callstatic = fe;
-       } else if (!strncmp(mname->val, ZEND_TOSTRING_FUNC_NAME, mname->len)) {
-               ce->__tostring = fe;
-       } else if (!strncmp(mname->val, ZEND_DEBUGINFO_FUNC_NAME, mname->len)) {
-               ce->__debugInfo = fe;
-       } else if (ce->name->len == mname->len) {
-               zend_string *lowercase_name = zend_string_alloc(ce->name->len, 0);
-               zend_str_tolower_copy(lowercase_name->val, ce->name->val, ce->name->len);
-               lowercase_name = zend_new_interned_string(lowercase_name TSRMLS_CC);
-               if (!memcmp(mname->val, lowercase_name->val, mname->len)) {
-                       if (ce->constructor) {
-                               zend_error_noreturn(E_COMPILE_ERROR, "%s has colliding constructor definitions coming from traits", ce->name->val);
-                       }
-                       ce->constructor = fe;
-                       fe->common.fn_flags |= ZEND_ACC_CTOR;
-               }
-               zend_string_release(lowercase_name);
-       }
-}
-/* }}} */
-
-static void zend_add_trait_method(zend_class_entry *ce, const char *name, zend_string *key, zend_function *fn, HashTable **overriden TSRMLS_DC) /* {{{ */
-{
-       zend_function *existing_fn = NULL;
-       zend_function *new_fn;
-
-       if ((existing_fn = zend_hash_find_ptr(&ce->function_table, key)) != NULL) {
-               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 ((existing_fn = zend_hash_find_ptr(*overriden, key)) != NULL) {
-                                       if (existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
-                                               /* Make sure the trait method is compatible with previosly declared abstract method */
-                                               if (!zend_traits_method_compatibility_check(fn, existing_fn TSRMLS_CC)) {
-                                                       zend_error_noreturn(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_noreturn(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, 8, NULL, ptr_dtor, 0, 0);
-                       }
-                       zend_hash_update_mem(*overriden, key, fn, sizeof(zend_function));
-                       return;
-               } else if (existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
-                       /* Make sure the trait method is compatible with previosly declared abstract method */
-                       if (!zend_traits_method_compatibility_check(fn, existing_fn TSRMLS_CC)) {
-                               zend_error_noreturn(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_noreturn(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 traits can't define the same non-abstract method */
-#if 1
-                       zend_error_noreturn(E_COMPILE_ERROR, "Trait method %s has not been applied, because there are collisions with other trait methods on %s",
-                               name, ce->name->val);
-#else          /* TODO: better error message */
-                       zend_error_noreturn(E_COMPILE_ERROR, "Trait method %s::%s has not been applied as %s::%s, because of collision with %s::%s",
-                               fn->common.scope->name->val, fn->common.function_name->val,
-                               ce->name->val, name,
-                               existing_fn->common.scope->name->val, existing_fn->common.function_name->val);
-#endif
-               } else {
-                       /* inherited members are overridden by members inserted by traits */
-                       /* check whether the trait method fulfills the inheritance requirements */
-                       do_inheritance_check_on_method(fn, existing_fn TSRMLS_CC);
-               }
-       }
-
-       function_add_ref(fn);
-       new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
-       memcpy(new_fn, fn, sizeof(zend_op_array));
-       fn = zend_hash_update_ptr(&ce->function_table, key, new_fn);
-       zend_add_magic_methods(ce, key, fn TSRMLS_CC);
-}
-/* }}} */
-
-static void zend_fixup_trait_method(zend_function *fn, zend_class_entry *ce) /* {{{ */
-{
-       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;
-               }
-               if (fn->op_array.static_variables) {
-                       ce->ce_flags |= ZEND_HAS_STATIC_IN_METHODS;
-               }
-       }
-}
-/* }}} */
-
-static int zend_traits_copy_functions(zend_string *fnname, zend_function *fn, zend_class_entry *ce, HashTable **overriden, HashTable *exclude_table TSRMLS_DC) /* {{{ */
-{
-       zend_trait_alias  *alias, **alias_ptr;
-       zend_string       *lcname;
-       zend_function      fn_copy;
-
-       /* apply aliases which are qualified with a class name, there should not be any ambiguity */
-       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 (alias->alias != NULL
-                               && (!alias->trait_method->ce || fn->common.scope == alias->trait_method->ce)
-                               && alias->trait_method->method_name->len == fnname->len
-                               && (zend_binary_strcasecmp(alias->trait_method->method_name->val, alias->trait_method->method_name->len, fnname->val, fnname->len) == 0)) {
-                               fn_copy = *fn;
-
-                               /* if it is 0, no modifieres has been changed */
-                               if (alias->modifiers) {
-                                       fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags ^ (fn->common.fn_flags & ZEND_ACC_PPP_MASK));
-                               }
-
-                               lcname = zend_string_alloc(alias->alias->len, 0);
-                               zend_str_tolower_copy(lcname->val, alias->alias->val, alias->alias->len);
-                               zend_add_trait_method(ce, alias->alias->val, lcname, &fn_copy, overriden TSRMLS_CC);
-                               zend_string_release(lcname);
-
-                               /* Record the trait from which this alias was resolved. */
-                               if (!alias->trait_method->ce) {
-                                       alias->trait_method->ce = fn->common.scope;
-                               }
-                       }
-                       alias_ptr++;
-                       alias = *alias_ptr;
-               }
-       }
-
-       if (exclude_table == NULL || zend_hash_find(exclude_table, fnname) == NULL) {
-               /* is not in hashtable, thus, function is not to be excluded */
-               fn_copy = *fn;
-
-               /* 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 (alias->alias == NULL && alias->modifiers != 0
-                                       && (!alias->trait_method->ce || fn->common.scope == alias->trait_method->ce)
-                                       && (alias->trait_method->method_name->len == fnname->len)
-                                       && (zend_binary_strcasecmp(alias->trait_method->method_name->val, alias->trait_method->method_name->len, fnname->val, 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 (!alias->trait_method->ce) {
-                                               alias->trait_method->ce = fn->common.scope;
-                                       }
-                               }
-                               alias_ptr++;
-                               alias = *alias_ptr;
-                       }
-               }
-
-               zend_add_trait_method(ce, fn->common.function_name->val, fnname, &fn_copy, overriden TSRMLS_CC);
-       }
-
-       return ZEND_HASH_APPLY_KEEP;
-}
-/* }}} */
-
-static void zend_check_trait_usage(zend_class_entry *ce, zend_class_entry *trait TSRMLS_DC) /* {{{ */
-{
-       uint32_t i;
-
-       if ((trait->ce_flags & ZEND_ACC_TRAIT) != ZEND_ACC_TRAIT) {
-               zend_error_noreturn(E_COMPILE_ERROR, "Class %s is not a trait, Only traits may be used in 'as' and 'insteadof' statements", trait->name->val);
-       }
-
-       for (i = 0; i < ce->num_traits; i++) {
-               if (ce->traits[i] == trait) {
-                       return;
-               }
-       }
-       zend_error_noreturn(E_COMPILE_ERROR, "Required Trait %s wasn't added to %s", trait->name->val, ce->name->val);
-}
-/* }}} */
-
-static void zend_traits_init_trait_structures(zend_class_entry *ce TSRMLS_DC) /* {{{ */
-{
-       size_t i, j = 0;
-       zend_trait_precedence *cur_precedence;
-       zend_trait_method_reference *cur_method_ref;
-       zend_string *lcname;
-       zend_bool method_exists;
-
-       /* resolve class references */
-       if (ce->trait_precedences) {
-               i = 0;
-               while ((cur_precedence = ce->trait_precedences[i])) {
-                       /** Resolve classes for all precedence operations. */
-                       if (cur_precedence->exclude_from_classes) {
-                               cur_method_ref = cur_precedence->trait_method;
-                               if (!(cur_precedence->trait_method->ce = zend_fetch_class(cur_method_ref->class_name,
-                                                               ZEND_FETCH_CLASS_TRAIT|ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC))) {
-                                       zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", cur_method_ref->class_name->val);
-                               }
-                               zend_check_trait_usage(ce, cur_precedence->trait_method->ce TSRMLS_CC);
-
-                               /** Ensure that the prefered method is actually available. */
-                               lcname = zend_string_alloc(cur_method_ref->method_name->len, 0);
-                               zend_str_tolower_copy(lcname->val, 
-                                       cur_method_ref->method_name->val,
-                                       cur_method_ref->method_name->len);
-                               method_exists = zend_hash_exists(&cur_method_ref->ce->function_table,
-                                                                                                lcname);
-                               zend_string_free(lcname);
-                               if (!method_exists) {
-                                       zend_error_noreturn(E_COMPILE_ERROR,
-                                                          "A precedence rule was defined for %s::%s but this method does not exist",
-                                                          cur_method_ref->ce->name->val,
-                                                          cur_method_ref->method_name->val);
-                               }
-
-                               /** With the other traits, we are more permissive.
-                                       We do not give errors for those. This allows to be more
-                                       defensive in such definitions.
-                                       However, we want to make sure that the insteadof declaration
-                                       is consistent in itself.
-                                */
-                               j = 0;
-                               while (cur_precedence->exclude_from_classes[j].class_name) {
-                                       zend_string* class_name = cur_precedence->exclude_from_classes[j].class_name;
-
-                                       if (!(cur_precedence->exclude_from_classes[j].ce = zend_fetch_class(class_name, ZEND_FETCH_CLASS_TRAIT |ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC))) {
-                                               zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", class_name->val);
-                                       }
-                                       zend_check_trait_usage(ce, cur_precedence->exclude_from_classes[j].ce 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].ce) {
-                                               zend_error_noreturn(E_COMPILE_ERROR,
-                                                                  "Inconsistent insteadof definition. "
-                                                                  "The method %s is to be used from %s, but %s is also on the exclude list",
-                                                                  cur_method_ref->method_name->val,
-                                                                  cur_precedence->trait_method->ce->name->val,
-                                                                  cur_precedence->trait_method->ce->name->val);
-                                       }
-
-                                       zend_string_release(class_name);
-                                       j++;
-                               }
-                       }
-                       i++;
-               }
-       }
-
-       if (ce->trait_aliases) {
-               i = 0;
-               while (ce->trait_aliases[i]) {
-                       /** For all aliases with an explicit class name, resolve the class now. */
-                       if (ce->trait_aliases[i]->trait_method->class_name) {
-                               cur_method_ref = ce->trait_aliases[i]->trait_method;
-                               if (!(cur_method_ref->ce = zend_fetch_class(cur_method_ref->class_name, ZEND_FETCH_CLASS_TRAIT|ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC))) {
-                                       zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", cur_method_ref->class_name->val);
-                               }
-                               zend_check_trait_usage(ce, cur_method_ref->ce TSRMLS_CC);
-
-                               /** And, ensure that the referenced method is resolvable, too. */
-                               lcname = zend_string_alloc(cur_method_ref->method_name->len, 0);
-                               zend_str_tolower_copy(lcname->val,
-                                       cur_method_ref->method_name->val,
-                                       cur_method_ref->method_name->len);
-                               method_exists = zend_hash_exists(&cur_method_ref->ce->function_table,
-                                               lcname);
-                               zend_string_free(lcname);
-
-                               if (!method_exists) {
-                                       zend_error_noreturn(E_COMPILE_ERROR, "An alias was defined for %s::%s but this method does not exist", cur_method_ref->ce->name->val, cur_method_ref->method_name->val);
-                               }
-                       }
-                       i++;
-               }
-       }
-}
-/* }}} */
-
-static void zend_traits_compile_exclude_table(HashTable* exclude_table, zend_trait_precedence **precedences, zend_class_entry *trait) /* {{{ */
-{
-       size_t i = 0, j;
-
-       if (!precedences) {
-               return;
-       }
-       while (precedences[i]) {
-               if (precedences[i]->exclude_from_classes) {
-                       j = 0;
-                       while (precedences[i]->exclude_from_classes[j].ce) {
-                               if (precedences[i]->exclude_from_classes[j].ce == trait) {
-                                       zend_string *lcname = zend_string_alloc(precedences[i]->trait_method->method_name->len, 0);
-                                                                               
-                                       zend_str_tolower_copy(lcname->val,
-                                               precedences[i]->trait_method->method_name->val,
-                                               precedences[i]->trait_method->method_name->len);
-                                       if (zend_hash_add_empty_element(exclude_table, lcname) == NULL) {
-                                               zend_string_release(lcname);
-                                               zend_error_noreturn(E_COMPILE_ERROR, "Failed to evaluate a trait precedence (%s). Method of trait %s was defined to be excluded multiple times", precedences[i]->trait_method->method_name->val, trait->name->val);
-                                       }
-                                       zend_string_release(lcname);
-                               }
-                               ++j;
-                       }
-               }
-               ++i;
-       }
-}
-/* }}} */
-
-static void zend_do_traits_method_binding(zend_class_entry *ce TSRMLS_DC) /* {{{ */
-{
-       uint32_t i;
-       HashTable *overriden = NULL;
-       zend_string *key;
-       zend_function *fn;
-
-       for (i = 0; i < ce->num_traits; i++) {
-               if (ce->trait_precedences) {
-                       HashTable exclude_table;
-
-                       /* TODO: revisit this start size, may be its not optimal */
-                       zend_hash_init_ex(&exclude_table, 8, 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_HASH_FOREACH_STR_KEY_PTR(&ce->traits[i]->function_table, key, fn) {
-                               zend_traits_copy_functions(key, fn, ce, &overriden, &exclude_table TSRMLS_CC);
-                       } ZEND_HASH_FOREACH_END();
-
-                       zend_hash_destroy(&exclude_table);
-               } else {
-                       ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->traits[i]->function_table, key, fn) {
-                               zend_traits_copy_functions(key, fn, ce, &overriden, NULL TSRMLS_CC);
-                       } ZEND_HASH_FOREACH_END();
-               }
-       }
-
-       ZEND_HASH_FOREACH_PTR(&ce->function_table, fn) {
-               zend_fixup_trait_method(fn, ce);
-       } ZEND_HASH_FOREACH_END();
-
-       if (overriden) {
-               zend_hash_destroy(overriden);
-               FREE_HASHTABLE(overriden);
-       }
-}
-/* }}} */
-
-static zend_class_entry* find_first_definition(zend_class_entry *ce, size_t current_trait, zend_string *prop_name, zend_class_entry *coliding_ce) /* {{{ */
-{
-       size_t i;
-
-       if (coliding_ce == ce) {
-               for (i = 0; i < current_trait; i++) {
-                       if (zend_hash_exists(&ce->traits[i]->properties_info, prop_name)) {
-                               return ce->traits[i];
-                       }
-               }
-       }
-
-       return coliding_ce;
-}
-/* }}} */
-
-static void zend_do_traits_property_binding(zend_class_entry *ce TSRMLS_DC) /* {{{ */
-{
-       size_t i;
-       zend_property_info *property_info;
-       zend_property_info *coliding_prop;
-       zval compare_result;
-       zend_string* prop_name;
-       const char* class_name_unused;
-       zend_bool not_compatible;
-       zval* prop_value;
-       uint32_t flags;
-       zend_string *doc_comment;
-
-       /* 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
-        * - if compatible, then strict notice
-        */
-       for (i = 0; i < ce->num_traits; i++) {
-               ZEND_HASH_FOREACH_PTR(&ce->traits[i]->properties_info, property_info) {
-                       /* first get the unmangeld name if necessary,
-                        * then check whether the property is already there
-                        */
-                       flags = property_info->flags;
-                       if ((flags & ZEND_ACC_PPP_MASK) == ZEND_ACC_PUBLIC) {
-                               prop_name = zend_string_copy(property_info->name);
-                       } else {
-                               const char *pname;
-                               size_t pname_len;
-
-                               /* for private and protected we need to unmangle the names */
-                               zend_unmangle_property_name_ex(property_info->name,
-                                                                                       &class_name_unused, &pname, &pname_len);
-                               prop_name = zend_string_init(pname, pname_len, 0);
-                       }
-
-                       /* next: check for conflicts with current class */
-                       if ((coliding_prop = zend_hash_find_ptr(&ce->properties_info, prop_name)) != NULL) {
-                               if (coliding_prop->flags & ZEND_ACC_SHADOW) {
-                                       zend_hash_del(&ce->properties_info, prop_name);
-                                       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 {
-                                                       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);
-                                               }
-                                       } else {
-                                               /* the flags are not identical, thus, we assume properties are not compatible */
-                                               not_compatible = 1;
-                                       }
-
-                                       if (not_compatible) {
-                                               zend_error_noreturn(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, coliding_prop->ce)->name->val,
-                                                               property_info->ce->name->val,
-                                                               prop_name->val,
-                                                               ce->name->val);
-                                       } 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, coliding_prop->ce)->name->val,
-                                                               property_info->ce->name->val,
-                                                               prop_name->val,
-                                                               ce->name->val);
-                                               zend_string_release(prop_name);
-                                               continue;
-                                       }
-                               }
-                       }
-
-                       /* property not found, so lets add it */
-                       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];
-                       }
-                       if (Z_REFCOUNTED_P(prop_value)) Z_ADDREF_P(prop_value);
-
-                       doc_comment = property_info->doc_comment ? zend_string_copy(property_info->doc_comment) : NULL;
-                       zend_declare_property_ex(ce, prop_name,
-                                                                        prop_value, flags,
-                                                                    doc_comment TSRMLS_CC);
-                       zend_string_release(prop_name);
-               } ZEND_HASH_FOREACH_END();
-       }
-}
-/* }}} */
-
-static void zend_do_check_for_inconsistent_traits_aliasing(zend_class_entry *ce TSRMLS_DC) /* {{{ */
-{
-       int i = 0;
-       zend_trait_alias* cur_alias;
-       zend_string* lc_method_name;
-
-       if (ce->trait_aliases) {
-               while (ce->trait_aliases[i]) {
-                       cur_alias = ce->trait_aliases[i];
-                       /** The trait for this alias has not been resolved, this means, this
-                               alias was not applied. Abort with an error. */
-                       if (!cur_alias->trait_method->ce) {
-                               if (cur_alias->alias) {
-                                       /** Plain old inconsistency/typo/bug */
-                                       zend_error_noreturn(E_COMPILE_ERROR,
-                                                          "An alias (%s) was defined for method %s(), but this method does not exist",
-                                                          cur_alias->alias->val,
-                                                          cur_alias->trait_method->method_name->val);
-                               } else {
-                                       /** Here are two possible cases:
-                                               1) this is an attempt to modifiy the visibility
-                                                  of a method introduce as part of another alias.
-                                                  Since that seems to violate the DRY principle,
-                                                  we check against it and abort.
-                                               2) it is just a plain old inconsitency/typo/bug
-                                                  as in the case where alias is set. */
-
-                                       lc_method_name = zend_string_alloc(cur_alias->trait_method->method_name->len, 0);
-                                       zend_str_tolower_copy(
-                                               lc_method_name->val,
-                                               cur_alias->trait_method->method_name->val,
-                                               cur_alias->trait_method->method_name->len);
-                                       if (zend_hash_exists(&ce->function_table,
-                                                                                lc_method_name)) {
-                                               zend_string_free(lc_method_name);
-                                               zend_error_noreturn(E_COMPILE_ERROR,
-                                                                  "The modifiers for the trait alias %s() need to be changed in the same statment in which the alias is defined. Error",
-                                                                  cur_alias->trait_method->method_name->val);
-                                       } else {
-                                               zend_string_free(lc_method_name);
-                                               zend_error_noreturn(E_COMPILE_ERROR,
-                                                                  "The modifiers of the trait method %s() are changed, but this method does not exist. Error",
-                                                                  cur_alias->trait_method->method_name->val);
-
-                                       }
-                               }
-                       }
-                       i++;
-               }
-       }
-}
-/* }}} */
-
-ZEND_API void zend_do_bind_traits(zend_class_entry *ce TSRMLS_DC) /* {{{ */
-{
-
-       if (ce->num_traits <= 0) {
-               return;
-       }
-
-       /* complete initialization of trait strutures in ce */
-       zend_traits_init_trait_structures(ce TSRMLS_CC);
-
-       /* first care about all methods to be flattened into the class */
-       zend_do_traits_method_binding(ce TSRMLS_CC);
-
-       /* Aliases which have not been applied indicate typos/bugs. */
-       zend_do_check_for_inconsistent_traits_aliasing(ce TSRMLS_CC);
-
-       /* then flatten the properties into it, to, mostly to notfiy developer about problems */
-       zend_do_traits_property_binding(ce TSRMLS_CC);
-
-       /* verify that all abstract methods from traits have been implemented */
-       zend_verify_abstract_class(ce TSRMLS_CC);
-
-       /* now everything should be fine and an added ZEND_ACC_IMPLICIT_ABSTRACT_CLASS should be removed */
-       if (ce->ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) {
-               ce->ce_flags -= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
-       }
-}
-/* }}} */
-
 ZEND_API int do_bind_function(const zend_op_array *op_array, const zend_op *opline, HashTable *function_table, zend_bool compile_time TSRMLS_DC) /* {{{ */
 {
        zend_function *function, *new_function;
index 10143d9efb26149d0bd76da60616b0bbd90634c8..3ba37c3b0eb8460a3754e7527c75d4380eb68baa 100644 (file)
@@ -449,14 +449,6 @@ void zend_do_free(znode *op1 TSRMLS_DC);
 ZEND_API int do_bind_function(const zend_op_array *op_array, const zend_op *opline, HashTable *function_table, zend_bool compile_time TSRMLS_DC);
 ZEND_API zend_class_entry *do_bind_class(const zend_op_array *op_array, const zend_op *opline, HashTable *class_table, zend_bool compile_time TSRMLS_DC);
 ZEND_API zend_class_entry *do_bind_inherited_class(const zend_op_array *op_array, const zend_op *opline, HashTable *class_table, zend_class_entry *parent_ce, zend_bool compile_time TSRMLS_DC);
-ZEND_API void zend_do_inherit_interfaces(zend_class_entry *ce, const zend_class_entry *iface TSRMLS_DC);
-ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry *iface 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);
-
-ZEND_API void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent_ce TSRMLS_DC);
-void zend_do_early_binding(TSRMLS_D);
 ZEND_API void zend_do_delayed_early_binding(const zend_op_array *op_array TSRMLS_DC);
 
 /* Functions for a null terminated pointer list, used for traits parsing and compilation */
index 8052f903ca81d2e3bc16a1badd081818113f6a2e..700b986d617a758b06a7d4e3a3db2f4cccf34684 100644 (file)
@@ -38,6 +38,7 @@
 #include "zend_generators.h"
 #include "zend_vm.h"
 #include "zend_dtrace.h"
+#include "zend_inheritance.h"
 
 /* Virtual current working directory support */
 #include "zend_virtual_cwd.h"
diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c
new file mode 100644 (file)
index 0000000..62cb3cc
--- /dev/null
@@ -0,0 +1,1574 @@
+/*
+   +----------------------------------------------------------------------+
+   | Zend Engine                                                          |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1998-2014 Zend Technologies Ltd. (http://www.zend.com) |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 2.00 of the Zend license,     |
+   | that is bundled with this package in the file LICENSE, and is        |
+   | available through the world-wide-web at the following url:           |
+   | http://www.zend.com/license/2_00.txt.                                |
+   | If you did not receive a copy of the Zend license and are unable to  |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@zend.com so we can mail you a copy immediately.              |
+   +----------------------------------------------------------------------+
+   | Authors: Andi Gutmans <andi@zend.com>                                |
+   |          Zeev Suraski <zeev@zend.com>                                |
+   +----------------------------------------------------------------------+
+*/
+
+#include "zend.h"
+#include "zend_API.h"
+#include "zend_compile.h"
+#include "zend_execute.h"
+
+static void ptr_dtor(zval *zv) /* {{{ */
+{
+       efree(Z_PTR_P(zv));
+}
+/* }}} */
+
+static zend_property_info *zend_duplicate_property_info(zend_property_info *property_info TSRMLS_DC) /* {{{ */
+{
+       zend_property_info* new_property_info;
+       
+       new_property_info = zend_arena_alloc(&CG(arena), sizeof(zend_property_info));
+       memcpy(new_property_info, property_info, sizeof(zend_property_info));
+       zend_string_addref(new_property_info->name);
+       if (new_property_info->doc_comment) {
+               zend_string_addref(new_property_info->doc_comment);
+       }
+       return new_property_info;
+}
+/* }}} */
+
+static zend_property_info *zend_duplicate_property_info_internal(zend_property_info *property_info) /* {{{ */
+{
+       zend_property_info* new_property_info = pemalloc(sizeof(zend_property_info), 1);
+       memcpy(new_property_info, property_info, sizeof(zend_property_info));
+       zend_string_addref(new_property_info->name);
+       return new_property_info;
+}
+/* }}} */
+
+static void do_inherit_parent_constructor(zend_class_entry *ce TSRMLS_DC) /* {{{ */
+{
+       zend_function *function, *new_function;
+
+       if (!ce->parent) {
+               return;
+       }
+
+       /* You cannot change create_object */
+       ce->create_object = ce->parent->create_object;
+
+       /* Inherit special functions if needed */
+       if (!ce->get_iterator) {
+               ce->get_iterator = ce->parent->get_iterator;
+       }
+       if (!ce->iterator_funcs.funcs) {
+               ce->iterator_funcs.funcs = ce->parent->iterator_funcs.funcs;
+       }
+       if (!ce->__get) {
+               ce->__get   = ce->parent->__get;
+       }
+       if (!ce->__set) {
+               ce->__set = ce->parent->__set;
+       }
+       if (!ce->__unset) {
+               ce->__unset = ce->parent->__unset;
+       }
+       if (!ce->__isset) {
+               ce->__isset = ce->parent->__isset;
+       }
+       if (!ce->__call) {
+               ce->__call = ce->parent->__call;
+       }
+       if (!ce->__callstatic) {
+               ce->__callstatic = ce->parent->__callstatic;
+       }
+       if (!ce->__tostring) {
+               ce->__tostring = ce->parent->__tostring;
+       }
+       if (!ce->clone) {
+               ce->clone = ce->parent->clone;
+       }
+       if(!ce->serialize) {
+               ce->serialize = ce->parent->serialize;
+       }
+       if(!ce->unserialize) {
+               ce->unserialize = ce->parent->unserialize;
+       }
+       if (!ce->destructor) {
+               ce->destructor   = ce->parent->destructor;
+       }
+       if (!ce->__debugInfo) {
+               ce->__debugInfo = ce->parent->__debugInfo;
+       }
+       if (ce->constructor) {
+               if (ce->parent->constructor && ce->parent->constructor->common.fn_flags & ZEND_ACC_FINAL) {
+                       zend_error(E_ERROR, "Cannot override final %s::%s() with %s::%s()",
+                               ce->parent->name->val, ce->parent->constructor->common.function_name->val,
+                               ce->name->val, ce->constructor->common.function_name->val
+                               );
+               }
+               return;
+       }
+
+       if ((function = zend_hash_str_find_ptr(&ce->parent->function_table, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1)) != NULL) {
+               /* inherit parent's constructor */
+               if (function->type == ZEND_INTERNAL_FUNCTION) {
+                       new_function = pemalloc(sizeof(zend_internal_function), 1);
+                       memcpy(new_function, function, sizeof(zend_internal_function));
+               } else {
+                       new_function = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
+                       memcpy(new_function, function, sizeof(zend_op_array));
+               }
+               zend_hash_str_update_ptr(&ce->function_table, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1, new_function);
+               function_add_ref(new_function);
+       } else {
+               /* Don't inherit the old style constructor if we already have the new style constructor */
+               zend_string *lc_class_name;
+               zend_string *lc_parent_class_name;
+
+               lc_class_name = zend_string_alloc(ce->name->len, 0);
+               zend_str_tolower_copy(lc_class_name->val, ce->name->val, ce->name->len);
+               if (!zend_hash_exists(&ce->function_table, lc_class_name)) {
+                       lc_parent_class_name = zend_string_alloc(ce->parent->name->len, 0);
+                       zend_str_tolower_copy(lc_parent_class_name->val, ce->parent->name->val, ce->parent->name->len);
+                       if (!zend_hash_exists(&ce->function_table, lc_parent_class_name) &&
+                                       (function = zend_hash_find_ptr(&ce->parent->function_table, lc_parent_class_name)) != NULL) {
+                               if (function->common.fn_flags & ZEND_ACC_CTOR) {
+                                       /* inherit parent's constructor */
+                                       new_function = pemalloc(sizeof(zend_function), function->type == ZEND_INTERNAL_FUNCTION);
+                                       memcpy(new_function, function, sizeof(zend_function));
+                                       zend_hash_update_ptr(&ce->function_table, lc_parent_class_name, new_function);
+                                       function_add_ref(new_function);
+                               }
+                       }
+                       zend_string_release(lc_parent_class_name);
+               }
+               zend_string_free(lc_class_name);
+       }
+       ce->constructor = ce->parent->constructor;
+}
+/* }}} */
+
+char *zend_visibility_string(uint32_t fn_flags) /* {{{ */
+{
+       if (fn_flags & ZEND_ACC_PRIVATE) {
+               return "private";
+       }
+       if (fn_flags & ZEND_ACC_PROTECTED) {
+               return "protected";
+       }
+       if (fn_flags & ZEND_ACC_PUBLIC) {
+               return "public";
+       }
+       return "";
+}
+/* }}} */
+
+static zend_function *do_inherit_method(zend_function *old_function TSRMLS_DC) /* {{{ */
+{
+       zend_function *new_function;
+
+       if (old_function->type == ZEND_INTERNAL_FUNCTION) {
+               new_function = pemalloc(sizeof(zend_internal_function), 1);
+               memcpy(new_function, old_function, sizeof(zend_internal_function));
+       } else {
+               new_function = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
+               memcpy(new_function, old_function, sizeof(zend_op_array));
+       }
+       /* The class entry of the derived function intentionally remains the same
+        * as that of the parent class.  That allows us to know in which context
+        * we're running, and handle private method calls properly.
+        */
+       function_add_ref(new_function);
+       return new_function;
+}
+/* }}} */
+
+static zend_bool zend_do_perform_implementation_check(const zend_function *fe, const zend_function *proto TSRMLS_DC) /* {{{ */
+{
+       uint32_t i, num_args;
+
+       /* If it's a user function then arg_info == NULL means we don't have any parameters but
+        * we still need to do the arg number checks.  We are only willing to ignore this for internal
+        * functions because extensions don't always define arg_info.
+        */
+       if (!proto || (!proto->common.arg_info && proto->common.type != ZEND_USER_FUNCTION)) {
+               return 1;
+       }
+
+       /* Checks for constructors only if they are declared in an interface,
+        * or explicitly marked as abstract
+        */
+       if ((fe->common.fn_flags & ZEND_ACC_CTOR)
+               && ((proto->common.scope->ce_flags & ZEND_ACC_INTERFACE) == 0
+                       && (proto->common.fn_flags & ZEND_ACC_ABSTRACT) == 0)) {
+               return 1;
+       }
+
+       /* If both methods are private do not enforce a signature */
+    if ((fe->common.fn_flags & ZEND_ACC_PRIVATE) && (proto->common.fn_flags & ZEND_ACC_PRIVATE)) {
+               return 1;
+       }
+
+       /* check number of arguments */
+       if (proto->common.required_num_args < fe->common.required_num_args
+               || proto->common.num_args > fe->common.num_args) {
+               return 0;
+       }
+
+       /* by-ref constraints on return values are covariant */
+       if ((proto->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)
+               && !(fe->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)) {
+               return 0;
+       }
+
+       if ((proto->common.fn_flags & ZEND_ACC_VARIADIC)
+               && !(fe->common.fn_flags & ZEND_ACC_VARIADIC)) {
+               return 0;
+       }
+
+       /* For variadic functions any additional (optional) arguments that were added must be
+        * checked against the signature of the variadic argument, so in this case we have to
+        * go through all the parameters of the function and not just those present in the
+        * prototype. */
+       num_args = proto->common.num_args;
+       if ((proto->common.fn_flags & ZEND_ACC_VARIADIC)
+               && fe->common.num_args > proto->common.num_args) {
+               num_args = fe->common.num_args;
+       }
+
+       for (i = 0; i < num_args; i++) {
+               zend_arg_info *fe_arg_info = &fe->common.arg_info[i];
+
+               zend_arg_info *proto_arg_info;
+               if (i < proto->common.num_args) {
+                       proto_arg_info = &proto->common.arg_info[i];
+               } else {
+                       proto_arg_info = &proto->common.arg_info[proto->common.num_args-1];
+               }
+
+               if (ZEND_LOG_XOR(fe_arg_info->class_name, proto_arg_info->class_name)) {
+                       /* Only one has a type hint and the other one doesn't */
+                       return 0;
+               }
+
+               if (fe_arg_info->class_name) {
+                       zend_string *fe_class_name, *proto_class_name;
+
+                       if (!strcasecmp(fe_arg_info->class_name, "parent") && proto->common.scope) {
+                               fe_class_name = zend_string_copy(proto->common.scope->name);
+                       } else if (!strcasecmp(fe_arg_info->class_name, "self") && fe->common.scope) {
+                               fe_class_name = zend_string_copy(fe->common.scope->name);
+                       } else {
+                               fe_class_name = zend_string_init(
+                                       fe_arg_info->class_name,
+                                       fe_arg_info->class_name_len, 0);
+                       }
+
+                       if (!strcasecmp(proto_arg_info->class_name, "parent") && proto->common.scope && proto->common.scope->parent) {
+                               proto_class_name = zend_string_copy(proto->common.scope->parent->name);
+                       } else if (!strcasecmp(proto_arg_info->class_name, "self") && proto->common.scope) {
+                               proto_class_name = zend_string_copy(proto->common.scope->name);
+                       } else {
+                               proto_class_name = zend_string_init(
+                                       proto_arg_info->class_name,
+                                       proto_arg_info->class_name_len, 0);
+                       }
+
+                       if (strcasecmp(fe_class_name->val, proto_class_name->val)!=0) {
+                               const char *colon;
+
+                               if (fe->common.type != ZEND_USER_FUNCTION) {
+                                       zend_string_release(proto_class_name);
+                                       zend_string_release(fe_class_name);
+                                       return 0;
+                           } else if (strchr(proto_class_name->val, '\\') != NULL ||
+                                               (colon = zend_memrchr(fe_class_name->val, '\\', fe_class_name->len)) == NULL ||
+                                               strcasecmp(colon+1, proto_class_name->val) != 0) {
+                                       zend_class_entry *fe_ce, *proto_ce;
+
+                                       fe_ce = zend_lookup_class(fe_class_name TSRMLS_CC);
+                                       proto_ce = zend_lookup_class(proto_class_name TSRMLS_CC);
+
+                                       /* Check for class alias */
+                                       if (!fe_ce || !proto_ce ||
+                                                       fe_ce->type == ZEND_INTERNAL_CLASS ||
+                                                       proto_ce->type == ZEND_INTERNAL_CLASS ||
+                                                       fe_ce != proto_ce) {
+                                               zend_string_release(proto_class_name);
+                                               zend_string_release(fe_class_name);
+                                               return 0;
+                                       }
+                               }
+                       }
+                       zend_string_release(proto_class_name);
+                       zend_string_release(fe_class_name);
+               }
+               if (fe_arg_info->type_hint != proto_arg_info->type_hint) {
+                       /* Incompatible type hint */
+                       return 0;
+               }
+
+               /* by-ref constraints on arguments are invariant */
+               if (fe_arg_info->pass_by_reference != proto_arg_info->pass_by_reference) {
+                       return 0;
+               }
+       }
+
+       return 1;
+}
+/* }}} */
+
+#define REALLOC_BUF_IF_EXCEED(buf, offset, length, size) \
+       if (UNEXPECTED(offset - buf + size >= length)) {        \
+               length += size + 1;                             \
+               buf = erealloc(buf, length);            \
+       }
+
+static char *zend_get_function_declaration(zend_function *fptr TSRMLS_DC) /* {{{ */
+{
+       char *offset, *buf;
+       uint32_t length = 1024;
+
+       offset = buf = (char *)emalloc(length * sizeof(char));
+       if (fptr->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) {
+               *(offset++) = '&';
+               *(offset++) = ' ';
+       }
+
+       if (fptr->common.scope) {
+               memcpy(offset, fptr->common.scope->name->val, fptr->common.scope->name->len);
+               offset += fptr->common.scope->name->len;
+               *(offset++) = ':';
+               *(offset++) = ':';
+       }
+
+       {
+               size_t name_len = fptr->common.function_name->len;
+               REALLOC_BUF_IF_EXCEED(buf, offset, length, name_len);
+               memcpy(offset, fptr->common.function_name->val, name_len);
+               offset += name_len;
+       }
+
+       *(offset++) = '(';
+       if (fptr->common.arg_info) {
+               uint32_t i, required;
+               zend_arg_info *arg_info = fptr->common.arg_info;
+
+               required = fptr->common.required_num_args;
+               for (i = 0; i < fptr->common.num_args;) {
+                       if (arg_info->class_name) {
+                               const char *class_name;
+                               uint32_t class_name_len;
+                               if (!strcasecmp(arg_info->class_name, "self") && fptr->common.scope ) {
+                                       class_name = fptr->common.scope->name->val;
+                                       class_name_len = fptr->common.scope->name->len;
+                               } else if (!strcasecmp(arg_info->class_name, "parent") && fptr->common.scope->parent) {
+                                       class_name = fptr->common.scope->parent->name->val;
+                                       class_name_len = fptr->common.scope->parent->name->len;
+                               } else {
+                                       class_name = arg_info->class_name;
+                                       class_name_len = arg_info->class_name_len;
+                               }
+                               REALLOC_BUF_IF_EXCEED(buf, offset, length, class_name_len);
+                               memcpy(offset, class_name, class_name_len);
+                               offset += class_name_len;
+                               *(offset++) = ' ';
+                       } else if (arg_info->type_hint) {
+                               uint32_t type_name_len;
+                               char *type_name = zend_get_type_by_const(arg_info->type_hint);
+                               type_name_len = strlen(type_name);
+                               REALLOC_BUF_IF_EXCEED(buf, offset, length, type_name_len);
+                               memcpy(offset, type_name, type_name_len);
+                               offset += type_name_len;
+                               *(offset++) = ' ';
+                       }
+
+                       if (arg_info->pass_by_reference) {
+                               *(offset++) = '&';
+                       }
+
+                       if (arg_info->is_variadic) {
+                               *(offset++) = '.';
+                               *(offset++) = '.';
+                               *(offset++) = '.';
+                       }
+
+                       *(offset++) = '$';
+
+                       if (arg_info->name) {
+                               REALLOC_BUF_IF_EXCEED(buf, offset, length, arg_info->name_len);
+                               memcpy(offset, arg_info->name, arg_info->name_len);
+                               offset += arg_info->name_len;
+                       } else {
+                               uint32_t idx = i;
+                               memcpy(offset, "param", 5);
+                               offset += 5;
+                               do {
+                                       *(offset++) = (char) (idx % 10) + '0';
+                                       idx /= 10;
+                               } while (idx > 0);
+                       }
+                       if (i >= required && !arg_info->is_variadic) {
+                               *(offset++) = ' ';
+                               *(offset++) = '=';
+                               *(offset++) = ' ';
+                               if (fptr->type == ZEND_USER_FUNCTION) {
+                                       zend_op *precv = NULL;
+                                       {
+                                               uint32_t idx  = i;
+                                               zend_op *op = ((zend_op_array *)fptr)->opcodes;
+                                               zend_op *end = op + ((zend_op_array *)fptr)->last;
+
+                                               ++idx;
+                                               while (op < end) {
+                                                       if ((op->opcode == ZEND_RECV || op->opcode == ZEND_RECV_INIT)
+                                                                       && op->op1.num == (zend_ulong)idx)
+                                                       {
+                                                               precv = op;
+                                                       }
+                                                       ++op;
+                                               }
+                                       }
+                                       if (precv && precv->opcode == ZEND_RECV_INIT && precv->op2_type != IS_UNUSED) {
+                                               zval *zv = precv->op2.zv;
+
+                                               if (Z_TYPE_P(zv) == IS_CONSTANT) {
+                                                       REALLOC_BUF_IF_EXCEED(buf, offset, length, Z_STRLEN_P(zv));
+                                                       memcpy(offset, Z_STRVAL_P(zv), Z_STRLEN_P(zv));
+                                                       offset += Z_STRLEN_P(zv);
+                                               } else if (Z_TYPE_P(zv) == IS_FALSE) {
+                                                       memcpy(offset, "false", 5);
+                                                       offset += 5;
+                                               } else if (Z_TYPE_P(zv) == IS_TRUE) {
+                                                       memcpy(offset, "true", 4);
+                                                       offset += 4;
+                                               } else if (Z_TYPE_P(zv) == IS_NULL) {
+                                                       memcpy(offset, "NULL", 4);
+                                                       offset += 4;
+                                               } else if (Z_TYPE_P(zv) == IS_STRING) {
+                                                       *(offset++) = '\'';
+                                                       REALLOC_BUF_IF_EXCEED(buf, offset, length, MIN(Z_STRLEN_P(zv), 10));
+                                                       memcpy(offset, Z_STRVAL_P(zv), MIN(Z_STRLEN_P(zv), 10));
+                                                       offset += MIN(Z_STRLEN_P(zv), 10);
+                                                       if (Z_STRLEN_P(zv) > 10) {
+                                                               *(offset++) = '.';
+                                                               *(offset++) = '.';
+                                                               *(offset++) = '.';
+                                                       }
+                                                       *(offset++) = '\'';
+                                               } else if (Z_TYPE_P(zv) == IS_ARRAY) {
+                                                       memcpy(offset, "Array", 5);
+                                                       offset += 5;
+                                               } else if (Z_TYPE_P(zv) == IS_CONSTANT_AST) {
+                                                       memcpy(offset, "<expression>", 12);
+                                                       offset += 12;
+                                               } else {
+                                                       zend_string *str = zval_get_string(zv);
+                                                       REALLOC_BUF_IF_EXCEED(buf, offset, length, str->len);
+                                                       memcpy(offset, str->val, str->len);
+                                                       offset += str->len;
+                                                       zend_string_release(str);
+                                               }
+                                       }
+                               } else {
+                                       memcpy(offset, "NULL", 4);
+                                       offset += 4;
+                               }
+                       }
+
+                       if (++i < fptr->common.num_args) {
+                               *(offset++) = ',';
+                               *(offset++) = ' ';
+                       }
+                       arg_info++;
+                       REALLOC_BUF_IF_EXCEED(buf, offset, length, 32);
+               }
+       }
+       *(offset++) = ')';
+       *offset = '\0';
+
+       return buf;
+}
+/* }}} */
+
+static void do_inheritance_check_on_method(zend_function *child, zend_function *parent TSRMLS_DC) /* {{{ */
+{
+       uint32_t child_flags;
+       uint32_t parent_flags = parent->common.fn_flags;
+
+       if ((parent->common.scope->ce_flags & ZEND_ACC_INTERFACE) == 0
+               && parent->common.fn_flags & ZEND_ACC_ABSTRACT
+               && parent->common.scope != (child->common.prototype ? child->common.prototype->common.scope : child->common.scope)
+               && child->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_IMPLEMENTED_ABSTRACT)) {
+               zend_error_noreturn(E_COMPILE_ERROR, "Can't inherit abstract function %s::%s() (previously declared abstract in %s)",
+                       parent->common.scope->name->val,
+                       child->common.function_name->val,
+                       child->common.prototype ? child->common.prototype->common.scope->name->val : child->common.scope->name->val);
+       }
+
+       if (parent_flags & ZEND_ACC_FINAL) {
+               zend_error_noreturn(E_COMPILE_ERROR, "Cannot override final method %s::%s()", ZEND_FN_SCOPE_NAME(parent), child->common.function_name->val);
+       }
+
+       child_flags     = child->common.fn_flags;
+       /* You cannot change from static to non static and vice versa.
+        */
+       if ((child_flags & ZEND_ACC_STATIC) != (parent_flags & ZEND_ACC_STATIC)) {
+               if (child->common.fn_flags & ZEND_ACC_STATIC) {
+                       zend_error_noreturn(E_COMPILE_ERROR, "Cannot make non static method %s::%s() static in class %s", ZEND_FN_SCOPE_NAME(parent), child->common.function_name->val, ZEND_FN_SCOPE_NAME(child));
+               } else {
+                       zend_error_noreturn(E_COMPILE_ERROR, "Cannot make static method %s::%s() non static in class %s", ZEND_FN_SCOPE_NAME(parent), child->common.function_name->val, ZEND_FN_SCOPE_NAME(child));
+               }
+       }
+
+       /* Disallow making an inherited method abstract. */
+       if ((child_flags & ZEND_ACC_ABSTRACT) && !(parent_flags & ZEND_ACC_ABSTRACT)) {
+               zend_error_noreturn(E_COMPILE_ERROR, "Cannot make non abstract method %s::%s() abstract in class %s", ZEND_FN_SCOPE_NAME(parent), child->common.function_name->val, ZEND_FN_SCOPE_NAME(child));
+       }
+
+       if (parent_flags & ZEND_ACC_CHANGED) {
+               child->common.fn_flags |= ZEND_ACC_CHANGED;
+       } else {
+               /* Prevent derived classes from restricting access that was available in parent classes
+                */
+               if ((child_flags & ZEND_ACC_PPP_MASK) > (parent_flags & ZEND_ACC_PPP_MASK)) {
+                       zend_error_noreturn(E_COMPILE_ERROR, "Access level to %s::%s() must be %s (as in class %s)%s", ZEND_FN_SCOPE_NAME(child), child->common.function_name->val, zend_visibility_string(parent_flags), ZEND_FN_SCOPE_NAME(parent), (parent_flags&ZEND_ACC_PUBLIC) ? "" : " or weaker");
+               } else if (((child_flags & ZEND_ACC_PPP_MASK) < (parent_flags & ZEND_ACC_PPP_MASK))
+                       && ((parent_flags & ZEND_ACC_PPP_MASK) & ZEND_ACC_PRIVATE)) {
+                       child->common.fn_flags |= ZEND_ACC_CHANGED;
+               }
+       }
+
+       if (parent_flags & ZEND_ACC_PRIVATE) {
+               child->common.prototype = NULL;
+       } else if (parent_flags & ZEND_ACC_ABSTRACT) {
+               child->common.fn_flags |= ZEND_ACC_IMPLEMENTED_ABSTRACT;
+               child->common.prototype = parent;
+       } else if (!(parent->common.fn_flags & ZEND_ACC_CTOR) || (parent->common.prototype && (parent->common.prototype->common.scope->ce_flags & ZEND_ACC_INTERFACE))) {
+               /* ctors only have a prototype if it comes from an interface */
+               child->common.prototype = parent->common.prototype ? parent->common.prototype : parent;
+       }
+
+       if (child->common.prototype && (child->common.prototype->common.fn_flags & ZEND_ACC_ABSTRACT)) {
+               if (!zend_do_perform_implementation_check(child, child->common.prototype TSRMLS_CC)) {
+                       zend_error_noreturn(E_COMPILE_ERROR, "Declaration of %s::%s() must be compatible with %s", ZEND_FN_SCOPE_NAME(child), child->common.function_name->val, zend_get_function_declaration(child->common.prototype TSRMLS_CC));
+               }
+       } else if (EG(error_reporting) & E_STRICT || Z_TYPE(EG(user_error_handler)) != IS_UNDEF) { /* Check E_STRICT (or custom error handler) before the check so that we save some time */
+               if (!zend_do_perform_implementation_check(child, parent TSRMLS_CC)) {
+                       char *method_prototype = zend_get_function_declaration(parent TSRMLS_CC);
+                       zend_error(E_STRICT, "Declaration of %s::%s() should be compatible with %s", ZEND_FN_SCOPE_NAME(child), child->common.function_name->val, method_prototype);
+                       efree(method_prototype);
+               }
+       }
+}
+/* }}} */
+
+static zend_bool do_inherit_method_check(HashTable *child_function_table, zend_function *parent, zend_string *key, zend_class_entry *child_ce) /* {{{ */
+{
+       uint32_t parent_flags = parent->common.fn_flags;
+       zend_function *child;
+       TSRMLS_FETCH();
+
+       if ((child = zend_hash_find_ptr(child_function_table, key)) == NULL) {
+               if (parent_flags & (ZEND_ACC_ABSTRACT)) {
+                       child_ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
+               }
+               return 1; /* method doesn't exist in child, copy from parent */
+       }
+
+       do_inheritance_check_on_method(child, parent TSRMLS_CC);
+
+       return 0;
+}
+/* }}} */
+
+static zend_bool do_inherit_property_access_check(HashTable *target_ht, zend_property_info *parent_info, zend_string *key, zend_class_entry *ce TSRMLS_DC) /* {{{ */
+{
+       zend_property_info *child_info;
+       zend_class_entry *parent_ce = ce->parent;
+
+       if (parent_info->flags & (ZEND_ACC_PRIVATE|ZEND_ACC_SHADOW)) {
+               if ((child_info = zend_hash_find_ptr(&ce->properties_info, key)) != NULL) {
+                       child_info->flags |= ZEND_ACC_CHANGED;
+               } else {
+                       if(ce->type & ZEND_INTERNAL_CLASS) {
+                               child_info = zend_duplicate_property_info_internal(parent_info);
+                       } else {
+                               child_info = zend_duplicate_property_info(parent_info TSRMLS_CC);
+                       }
+                       zend_hash_update_ptr(&ce->properties_info, key, child_info);
+                       child_info->flags &= ~ZEND_ACC_PRIVATE; /* it's not private anymore */
+                       child_info->flags |= ZEND_ACC_SHADOW; /* but it's a shadow of private */
+               }
+               return 0; /* don't copy access information to child */
+       }
+
+       if ((child_info = zend_hash_find_ptr(&ce->properties_info, key)) != NULL) {
+               if ((parent_info->flags & ZEND_ACC_STATIC) != (child_info->flags & ZEND_ACC_STATIC)) {
+                       zend_error_noreturn(E_COMPILE_ERROR, "Cannot redeclare %s%s::$%s as %s%s::$%s",
+                               (parent_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", parent_ce->name->val, key->val,
+                               (child_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", ce->name->val, key->val);
+
+               }
+
+               if(parent_info->flags & ZEND_ACC_CHANGED) {
+                       child_info->flags |= ZEND_ACC_CHANGED;
+               }
+
+               if ((child_info->flags & ZEND_ACC_PPP_MASK) > (parent_info->flags & ZEND_ACC_PPP_MASK)) {
+                       zend_error_noreturn(E_COMPILE_ERROR, "Access level to %s::$%s must be %s (as in class %s)%s", ce->name->val, key->val, zend_visibility_string(parent_info->flags), parent_ce->name->val, (parent_info->flags&ZEND_ACC_PUBLIC) ? "" : " or weaker");
+               } else if ((child_info->flags & ZEND_ACC_STATIC) == 0) {
+                       zval_ptr_dtor(&(ce->default_properties_table[parent_info->offset]));
+                       ce->default_properties_table[parent_info->offset] = ce->default_properties_table[child_info->offset];
+                       ZVAL_UNDEF(&ce->default_properties_table[child_info->offset]);
+                       child_info->offset = parent_info->offset;
+               }
+               return 0;       /* Don't copy from parent */
+       } else {
+               return 1;       /* Copy from parent */
+       }
+}
+/* }}} */
+
+static inline void do_implement_interface(zend_class_entry *ce, zend_class_entry *iface TSRMLS_DC) /* {{{ */
+{
+       if (!(ce->ce_flags & ZEND_ACC_INTERFACE) && iface->interface_gets_implemented && iface->interface_gets_implemented(iface, ce TSRMLS_CC) == FAILURE) {
+               zend_error(E_CORE_ERROR, "Class %s could not implement interface %s", ce->name->val, iface->name->val);
+       }
+       if (ce == iface) {
+               zend_error(E_ERROR, "Interface %s cannot implement itself", ce->name->val);
+       }
+}
+/* }}} */
+
+ZEND_API void zend_do_inherit_interfaces(zend_class_entry *ce, const zend_class_entry *iface TSRMLS_DC) /* {{{ */
+{
+       /* expects interface to be contained in ce's interface list already */
+       uint32_t i, ce_num, if_num = iface->num_interfaces;
+       zend_class_entry *entry;
+
+       if (if_num==0) {
+               return;
+       }
+       ce_num = ce->num_interfaces;
+
+       if (ce->type == ZEND_INTERNAL_CLASS) {
+               ce->interfaces = (zend_class_entry **) realloc(ce->interfaces, sizeof(zend_class_entry *) * (ce_num + if_num));
+       } else {
+               ce->interfaces = (zend_class_entry **) erealloc(ce->interfaces, sizeof(zend_class_entry *) * (ce_num + if_num));
+       }
+
+       /* Inherit the interfaces, only if they're not already inherited by the class */
+       while (if_num--) {
+               entry = iface->interfaces[if_num];
+               for (i = 0; i < ce_num; i++) {
+                       if (ce->interfaces[i] == entry) {
+                               break;
+                       }
+               }
+               if (i == ce_num) {
+                       ce->interfaces[ce->num_interfaces++] = entry;
+               }
+       }
+
+       /* and now call the implementing handlers */
+       while (ce_num < ce->num_interfaces) {
+               do_implement_interface(ce, ce->interfaces[ce_num++] TSRMLS_CC);
+       }
+}
+/* }}} */
+
+#ifdef ZTS
+# define zval_property_ctor(parent_ce, ce) \
+       (((parent_ce)->type != (ce)->type) ? ZVAL_COPY_CTOR : zval_add_ref)
+#else
+# define zval_property_ctor(parent_ce, ce) \
+       zval_add_ref
+#endif
+
+static void do_inherit_class_constant(zend_string *name, zval *zv, zend_class_entry *ce, zend_class_entry *parent_ce TSRMLS_DC) /* {{{ */
+{
+       if (!Z_ISREF_P(zv)) {
+               if (parent_ce->type == ZEND_INTERNAL_CLASS) {
+                       ZVAL_NEW_PERSISTENT_REF(zv, zv);
+               } else {
+                       ZVAL_NEW_REF(zv, zv);
+               }
+       }
+       if (Z_CONSTANT_P(Z_REFVAL_P(zv))) {
+               ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
+       }
+       if (zend_hash_add(&ce->constants_table, name, zv)) {
+               Z_ADDREF_P(zv);
+       }
+}
+/* }}} */
+
+ZEND_API void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent_ce TSRMLS_DC) /* {{{ */
+{
+       zend_property_info *property_info;
+       zend_function *func;
+       zend_string *key;
+       zval *zv;
+
+       if ((ce->ce_flags & ZEND_ACC_INTERFACE)
+               && !(parent_ce->ce_flags & ZEND_ACC_INTERFACE)) {
+               zend_error_noreturn(E_COMPILE_ERROR, "Interface %s may not inherit from class (%s)", ce->name->val, parent_ce->name->val);
+       }
+       if (parent_ce->ce_flags & ZEND_ACC_FINAL_CLASS) {
+               zend_error_noreturn(E_COMPILE_ERROR, "Class %s may not inherit from final class (%s)", ce->name->val, parent_ce->name->val);
+       }
+
+       ce->parent = parent_ce;
+       /* Copy serialize/unserialize callbacks */
+       if (!ce->serialize) {
+               ce->serialize   = parent_ce->serialize;
+       }
+       if (!ce->unserialize) {
+               ce->unserialize = parent_ce->unserialize;
+       }
+
+       /* Inherit interfaces */
+       zend_do_inherit_interfaces(ce, parent_ce TSRMLS_CC);
+
+       /* Inherit properties */
+       if (parent_ce->default_properties_count) {
+               int i = ce->default_properties_count + parent_ce->default_properties_count;
+
+               ce->default_properties_table = perealloc(ce->default_properties_table, sizeof(zval) * i, ce->type == ZEND_INTERNAL_CLASS);
+               if (ce->default_properties_count) {
+                       while (i-- > parent_ce->default_properties_count) {
+                               ce->default_properties_table[i] = ce->default_properties_table[i - parent_ce->default_properties_count];
+                       }
+               }
+               for (i = 0; i < parent_ce->default_properties_count; i++) {
+#ifdef ZTS
+                       if (parent_ce->type != ce->type) {
+                               ZVAL_DUP(&ce->default_properties_table[i], &parent_ce->default_properties_table[i]);
+                               if (Z_OPT_CONSTANT(ce->default_properties_table[i])) {
+                                       ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
+                               }
+                               continue;
+                       }
+#endif
+
+                       ZVAL_COPY(&ce->default_properties_table[i], &parent_ce->default_properties_table[i]);
+                       if (Z_OPT_CONSTANT(ce->default_properties_table[i])) {
+                               ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
+                       }
+               }
+               ce->default_properties_count += parent_ce->default_properties_count;
+       }
+
+       if (parent_ce->type != ce->type) {
+               /* User class extends internal class */
+               zend_update_class_constants(parent_ce  TSRMLS_CC);
+               if (parent_ce->default_static_members_count) {
+                       int i = ce->default_static_members_count + parent_ce->default_static_members_count;
+
+                       ce->default_static_members_table = erealloc(ce->default_static_members_table, sizeof(zval) * i);
+                       if (ce->default_static_members_count) {
+                               while (i-- > parent_ce->default_static_members_count) {
+                                       ce->default_static_members_table[i] = ce->default_static_members_table[i - parent_ce->default_static_members_count];
+                               }
+                       }
+                       for (i = 0; i < parent_ce->default_static_members_count; i++) {
+                               ZVAL_MAKE_REF(&CE_STATIC_MEMBERS(parent_ce)[i]);
+                               ce->default_static_members_table[i] = CE_STATIC_MEMBERS(parent_ce)[i];
+                               Z_ADDREF(ce->default_static_members_table[i]);
+                               if (Z_CONSTANT_P(Z_REFVAL(ce->default_static_members_table[i]))) {
+                                       ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
+                               }
+                       }
+                       ce->default_static_members_count += parent_ce->default_static_members_count;
+                       ce->static_members_table = ce->default_static_members_table;
+               }
+       } else {
+               if (parent_ce->default_static_members_count) {
+                       int i = ce->default_static_members_count + parent_ce->default_static_members_count;
+
+                       ce->default_static_members_table = perealloc(ce->default_static_members_table, sizeof(zval) * i, ce->type == ZEND_INTERNAL_CLASS);
+                       if (ce->default_static_members_count) {
+                               while (i-- > parent_ce->default_static_members_count) {
+                                       ce->default_static_members_table[i] = ce->default_static_members_table[i - parent_ce->default_static_members_count];
+                               }
+                       }
+                       for (i = 0; i < parent_ce->default_static_members_count; i++) {
+                               ZVAL_MAKE_REF(&parent_ce->default_static_members_table[i]);
+                               ce->default_static_members_table[i] = parent_ce->default_static_members_table[i];
+                               Z_ADDREF(ce->default_static_members_table[i]);
+                               if (Z_CONSTANT_P(Z_REFVAL(ce->default_static_members_table[i]))) {
+                                       ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
+                               }
+                       }
+                       ce->default_static_members_count += parent_ce->default_static_members_count;
+                       if (ce->type == ZEND_USER_CLASS) {
+                               ce->static_members_table = ce->default_static_members_table;
+                       }
+               }
+       }
+
+       ZEND_HASH_FOREACH_PTR(&ce->properties_info, property_info) {
+               if (property_info->ce == ce) {
+                       if (property_info->flags & ZEND_ACC_STATIC) {
+                               property_info->offset += parent_ce->default_static_members_count;
+                       } else {
+                               property_info->offset += parent_ce->default_properties_count;
+                       }
+               }
+       } ZEND_HASH_FOREACH_END();
+
+       ZEND_HASH_FOREACH_STR_KEY_PTR(&parent_ce->properties_info, key, property_info) {
+               if (do_inherit_property_access_check(&ce->properties_info, property_info, key, ce TSRMLS_CC)) {
+                       if (ce->type & ZEND_INTERNAL_CLASS) {
+                               property_info = zend_duplicate_property_info_internal(property_info);
+                       } else {
+                               property_info = zend_duplicate_property_info(property_info TSRMLS_CC);
+                       }
+                       zend_hash_add_new_ptr(&ce->properties_info, key, property_info);
+               }
+       } ZEND_HASH_FOREACH_END();
+
+       ZEND_HASH_FOREACH_STR_KEY_VAL(&parent_ce->constants_table, key, zv) {
+               do_inherit_class_constant(key, zv, ce, parent_ce TSRMLS_CC);
+       } ZEND_HASH_FOREACH_END();
+
+       ZEND_HASH_FOREACH_STR_KEY_PTR(&parent_ce->function_table, key, func) {
+               if (do_inherit_method_check(&ce->function_table, func, key, ce)) {
+                       zend_function *new_func = do_inherit_method(func TSRMLS_CC);
+                       zend_hash_add_new_ptr(&ce->function_table, key, new_func);
+               }
+       } ZEND_HASH_FOREACH_END();
+
+       do_inherit_parent_constructor(ce TSRMLS_CC);
+
+       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|ZEND_ACC_IMPLEMENT_TRAITS))) {
+               /* The verification will be done in runtime by ZEND_VERIFY_ABSTRACT_CLASS */
+               zend_verify_abstract_class(ce TSRMLS_CC);
+       }
+       ce->ce_flags |= parent_ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS;
+}
+/* }}} */
+
+static zend_bool do_inherit_constant_check(HashTable *child_constants_table, zval *parent_constant, zend_string *name, const zend_class_entry *iface) /* {{{ */
+{
+       zval *old_constant;
+
+       if ((old_constant = zend_hash_find(child_constants_table, name)) != NULL) {
+               if (!Z_ISREF_P(old_constant) ||
+                   !Z_ISREF_P(parent_constant) ||
+                   Z_REFVAL_P(old_constant) != Z_REFVAL_P(parent_constant)) {
+                       zend_error_noreturn(E_COMPILE_ERROR, "Cannot inherit previously-inherited or override constant %s from interface %s", name->val, iface->name->val);
+               }
+               return 0;
+       }
+       return 1;
+}
+/* }}} */
+
+static void do_inherit_iface_constant(zend_string *name, zval *zv, zend_class_entry *ce, zend_class_entry *iface TSRMLS_DC) /* {{{ */
+{
+       if (do_inherit_constant_check(&ce->constants_table, zv, name, iface)) {
+               ZVAL_MAKE_REF(zv);
+               Z_ADDREF_P(zv);
+               if (Z_CONSTANT_P(Z_REFVAL_P(zv))) {
+                       ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
+               }
+               zend_hash_update(&ce->constants_table, name, zv);
+       }
+}
+/* }}} */
+
+ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry *iface TSRMLS_DC) /* {{{ */
+{
+       uint32_t i, ignore = 0;
+       uint32_t current_iface_num = ce->num_interfaces;
+       uint32_t parent_iface_num  = ce->parent ? ce->parent->num_interfaces : 0;
+       zend_function *func;
+       zend_string *key;
+       zval *zv;
+
+       for (i = 0; i < ce->num_interfaces; i++) {
+               if (ce->interfaces[i] == NULL) {
+                       memmove(ce->interfaces + i, ce->interfaces + i + 1, sizeof(zend_class_entry*) * (--ce->num_interfaces - i));
+                       i--;
+               } else if (ce->interfaces[i] == iface) {
+                       if (i < parent_iface_num) {
+                               ignore = 1;
+                       } else {
+                               zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot implement previously implemented interface %s", ce->name->val, iface->name->val);
+                       }
+               }
+       }
+       if (ignore) {
+               /* Check for attempt to redeclare interface constants */
+               ZEND_HASH_FOREACH_STR_KEY_VAL(&ce->constants_table, key, zv) {
+                       do_inherit_constant_check(&iface->constants_table, zv, key, iface);
+               } ZEND_HASH_FOREACH_END();
+       } else {
+               if (ce->num_interfaces >= current_iface_num) {
+                       if (ce->type == ZEND_INTERNAL_CLASS) {
+                               ce->interfaces = (zend_class_entry **) realloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num));
+                       } else {
+                               ce->interfaces = (zend_class_entry **) erealloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num));
+                       }
+               }
+               ce->interfaces[ce->num_interfaces++] = iface;
+
+               ZEND_HASH_FOREACH_STR_KEY_VAL(&iface->constants_table, key, zv) {
+                       do_inherit_iface_constant(key, zv, ce, iface TSRMLS_CC);
+               } ZEND_HASH_FOREACH_END();
+
+               ZEND_HASH_FOREACH_STR_KEY_PTR(&iface->function_table, key, func) {
+                       if (do_inherit_method_check(&ce->function_table, func, key, ce)) {
+                               zend_function *new_func = do_inherit_method(func TSRMLS_CC);
+                               zend_hash_add_new_ptr(&ce->function_table, key, new_func);
+                       }
+               } ZEND_HASH_FOREACH_END();
+
+               do_implement_interface(ce, iface TSRMLS_CC);
+               zend_do_inherit_interfaces(ce, iface TSRMLS_CC);
+       }
+}
+/* }}} */
+
+ZEND_API void zend_do_implement_trait(zend_class_entry *ce, zend_class_entry *trait TSRMLS_DC) /* {{{ */
+{
+       uint32_t i, ignore = 0;
+       uint32_t current_trait_num = ce->num_traits;
+       uint32_t parent_trait_num  = ce->parent ? ce->parent->num_traits : 0;
+
+       for (i = 0; i < ce->num_traits; i++) {
+               if (ce->traits[i] == NULL) {
+                       memmove(ce->traits + i, ce->traits + i + 1, sizeof(zend_class_entry*) * (--ce->num_traits - i));
+                       i--;
+               } else if (ce->traits[i] == trait) {
+                       if (i < parent_trait_num) {
+                               ignore = 1;
+                       }
+               }
+       }
+       if (!ignore) {
+               if (ce->num_traits >= current_trait_num) {
+                       if (ce->type == ZEND_INTERNAL_CLASS) {
+                               ce->traits = (zend_class_entry **) realloc(ce->traits, sizeof(zend_class_entry *) * (++current_trait_num));
+                       } else {
+                               ce->traits = (zend_class_entry **) erealloc(ce->traits, sizeof(zend_class_entry *) * (++current_trait_num));
+                       }
+               }
+               ce->traits[ce->num_traits++] = trait;
+       }
+}
+/* }}} */
+
+static zend_bool zend_traits_method_compatibility_check(zend_function *fn, zend_function *other_fn TSRMLS_DC) /* {{{ */
+{
+       uint32_t    fn_flags = fn->common.scope->ce_flags;
+       uint32_t other_flags = other_fn->common.scope->ce_flags;
+
+       return zend_do_perform_implementation_check(fn, other_fn TSRMLS_CC)
+               && ((other_fn->common.scope->ce_flags & ZEND_ACC_INTERFACE) || zend_do_perform_implementation_check(other_fn, fn TSRMLS_CC))
+               && ((fn_flags & (ZEND_ACC_FINAL|ZEND_ACC_STATIC)) ==
+                   (other_flags & (ZEND_ACC_FINAL|ZEND_ACC_STATIC))); /* equal final and static qualifier */
+}
+/* }}} */
+
+static void zend_add_magic_methods(zend_class_entry* ce, zend_string* mname, zend_function* fe TSRMLS_DC) /* {{{ */
+{
+       if (!strncmp(mname->val, ZEND_CLONE_FUNC_NAME, mname->len)) {
+               ce->clone = fe; fe->common.fn_flags |= ZEND_ACC_CLONE;
+       } else if (!strncmp(mname->val, ZEND_CONSTRUCTOR_FUNC_NAME, mname->len)) {
+               if (ce->constructor) {
+                       zend_error_noreturn(E_COMPILE_ERROR, "%s has colliding constructor definitions coming from traits", ce->name->val);
+               }
+               ce->constructor = fe; fe->common.fn_flags |= ZEND_ACC_CTOR;
+       } else if (!strncmp(mname->val, ZEND_DESTRUCTOR_FUNC_NAME,  mname->len)) {
+               ce->destructor = fe; fe->common.fn_flags |= ZEND_ACC_DTOR;
+       } else if (!strncmp(mname->val, ZEND_GET_FUNC_NAME, mname->len)) {
+               ce->__get = fe;
+       } else if (!strncmp(mname->val, ZEND_SET_FUNC_NAME, mname->len)) {
+               ce->__set = fe;
+       } else if (!strncmp(mname->val, ZEND_CALL_FUNC_NAME, mname->len)) {
+               ce->__call = fe;
+       } else if (!strncmp(mname->val, ZEND_UNSET_FUNC_NAME, mname->len)) {
+               ce->__unset = fe;
+       } else if (!strncmp(mname->val, ZEND_ISSET_FUNC_NAME, mname->len)) {
+               ce->__isset = fe;
+       } else if (!strncmp(mname->val, ZEND_CALLSTATIC_FUNC_NAME, mname->len)) {
+               ce->__callstatic = fe;
+       } else if (!strncmp(mname->val, ZEND_TOSTRING_FUNC_NAME, mname->len)) {
+               ce->__tostring = fe;
+       } else if (!strncmp(mname->val, ZEND_DEBUGINFO_FUNC_NAME, mname->len)) {
+               ce->__debugInfo = fe;
+       } else if (ce->name->len == mname->len) {
+               zend_string *lowercase_name = zend_string_alloc(ce->name->len, 0);
+               zend_str_tolower_copy(lowercase_name->val, ce->name->val, ce->name->len);
+               lowercase_name = zend_new_interned_string(lowercase_name TSRMLS_CC);
+               if (!memcmp(mname->val, lowercase_name->val, mname->len)) {
+                       if (ce->constructor) {
+                               zend_error_noreturn(E_COMPILE_ERROR, "%s has colliding constructor definitions coming from traits", ce->name->val);
+                       }
+                       ce->constructor = fe;
+                       fe->common.fn_flags |= ZEND_ACC_CTOR;
+               }
+               zend_string_release(lowercase_name);
+       }
+}
+/* }}} */
+
+static void zend_add_trait_method(zend_class_entry *ce, const char *name, zend_string *key, zend_function *fn, HashTable **overriden TSRMLS_DC) /* {{{ */
+{
+       zend_function *existing_fn = NULL;
+       zend_function *new_fn;
+
+       if ((existing_fn = zend_hash_find_ptr(&ce->function_table, key)) != NULL) {
+               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 ((existing_fn = zend_hash_find_ptr(*overriden, key)) != NULL) {
+                                       if (existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
+                                               /* Make sure the trait method is compatible with previosly declared abstract method */
+                                               if (!zend_traits_method_compatibility_check(fn, existing_fn TSRMLS_CC)) {
+                                                       zend_error_noreturn(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_noreturn(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, 8, NULL, ptr_dtor, 0, 0);
+                       }
+                       zend_hash_update_mem(*overriden, key, fn, sizeof(zend_function));
+                       return;
+               } else if (existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
+                       /* Make sure the trait method is compatible with previosly declared abstract method */
+                       if (!zend_traits_method_compatibility_check(fn, existing_fn TSRMLS_CC)) {
+                               zend_error_noreturn(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_noreturn(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 traits can't define the same non-abstract method */
+#if 1
+                       zend_error_noreturn(E_COMPILE_ERROR, "Trait method %s has not been applied, because there are collisions with other trait methods on %s",
+                               name, ce->name->val);
+#else          /* TODO: better error message */
+                       zend_error_noreturn(E_COMPILE_ERROR, "Trait method %s::%s has not been applied as %s::%s, because of collision with %s::%s",
+                               fn->common.scope->name->val, fn->common.function_name->val,
+                               ce->name->val, name,
+                               existing_fn->common.scope->name->val, existing_fn->common.function_name->val);
+#endif
+               } else {
+                       /* inherited members are overridden by members inserted by traits */
+                       /* check whether the trait method fulfills the inheritance requirements */
+                       do_inheritance_check_on_method(fn, existing_fn TSRMLS_CC);
+               }
+       }
+
+       function_add_ref(fn);
+       new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
+       memcpy(new_fn, fn, sizeof(zend_op_array));
+       fn = zend_hash_update_ptr(&ce->function_table, key, new_fn);
+       zend_add_magic_methods(ce, key, fn TSRMLS_CC);
+}
+/* }}} */
+
+static void zend_fixup_trait_method(zend_function *fn, zend_class_entry *ce) /* {{{ */
+{
+       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;
+               }
+               if (fn->op_array.static_variables) {
+                       ce->ce_flags |= ZEND_HAS_STATIC_IN_METHODS;
+               }
+       }
+}
+/* }}} */
+
+static int zend_traits_copy_functions(zend_string *fnname, zend_function *fn, zend_class_entry *ce, HashTable **overriden, HashTable *exclude_table TSRMLS_DC) /* {{{ */
+{
+       zend_trait_alias  *alias, **alias_ptr;
+       zend_string       *lcname;
+       zend_function      fn_copy;
+
+       /* apply aliases which are qualified with a class name, there should not be any ambiguity */
+       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 (alias->alias != NULL
+                               && (!alias->trait_method->ce || fn->common.scope == alias->trait_method->ce)
+                               && alias->trait_method->method_name->len == fnname->len
+                               && (zend_binary_strcasecmp(alias->trait_method->method_name->val, alias->trait_method->method_name->len, fnname->val, fnname->len) == 0)) {
+                               fn_copy = *fn;
+
+                               /* if it is 0, no modifieres has been changed */
+                               if (alias->modifiers) {
+                                       fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags ^ (fn->common.fn_flags & ZEND_ACC_PPP_MASK));
+                               }
+
+                               lcname = zend_string_alloc(alias->alias->len, 0);
+                               zend_str_tolower_copy(lcname->val, alias->alias->val, alias->alias->len);
+                               zend_add_trait_method(ce, alias->alias->val, lcname, &fn_copy, overriden TSRMLS_CC);
+                               zend_string_release(lcname);
+
+                               /* Record the trait from which this alias was resolved. */
+                               if (!alias->trait_method->ce) {
+                                       alias->trait_method->ce = fn->common.scope;
+                               }
+                       }
+                       alias_ptr++;
+                       alias = *alias_ptr;
+               }
+       }
+
+       if (exclude_table == NULL || zend_hash_find(exclude_table, fnname) == NULL) {
+               /* is not in hashtable, thus, function is not to be excluded */
+               fn_copy = *fn;
+
+               /* 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 (alias->alias == NULL && alias->modifiers != 0
+                                       && (!alias->trait_method->ce || fn->common.scope == alias->trait_method->ce)
+                                       && (alias->trait_method->method_name->len == fnname->len)
+                                       && (zend_binary_strcasecmp(alias->trait_method->method_name->val, alias->trait_method->method_name->len, fnname->val, 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 (!alias->trait_method->ce) {
+                                               alias->trait_method->ce = fn->common.scope;
+                                       }
+                               }
+                               alias_ptr++;
+                               alias = *alias_ptr;
+                       }
+               }
+
+               zend_add_trait_method(ce, fn->common.function_name->val, fnname, &fn_copy, overriden TSRMLS_CC);
+       }
+
+       return ZEND_HASH_APPLY_KEEP;
+}
+/* }}} */
+
+static void zend_check_trait_usage(zend_class_entry *ce, zend_class_entry *trait TSRMLS_DC) /* {{{ */
+{
+       uint32_t i;
+
+       if ((trait->ce_flags & ZEND_ACC_TRAIT) != ZEND_ACC_TRAIT) {
+               zend_error_noreturn(E_COMPILE_ERROR, "Class %s is not a trait, Only traits may be used in 'as' and 'insteadof' statements", trait->name->val);
+       }
+
+       for (i = 0; i < ce->num_traits; i++) {
+               if (ce->traits[i] == trait) {
+                       return;
+               }
+       }
+       zend_error_noreturn(E_COMPILE_ERROR, "Required Trait %s wasn't added to %s", trait->name->val, ce->name->val);
+}
+/* }}} */
+
+static void zend_traits_init_trait_structures(zend_class_entry *ce TSRMLS_DC) /* {{{ */
+{
+       size_t i, j = 0;
+       zend_trait_precedence *cur_precedence;
+       zend_trait_method_reference *cur_method_ref;
+       zend_string *lcname;
+       zend_bool method_exists;
+
+       /* resolve class references */
+       if (ce->trait_precedences) {
+               i = 0;
+               while ((cur_precedence = ce->trait_precedences[i])) {
+                       /** Resolve classes for all precedence operations. */
+                       if (cur_precedence->exclude_from_classes) {
+                               cur_method_ref = cur_precedence->trait_method;
+                               if (!(cur_precedence->trait_method->ce = zend_fetch_class(cur_method_ref->class_name,
+                                                               ZEND_FETCH_CLASS_TRAIT|ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC))) {
+                                       zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", cur_method_ref->class_name->val);
+                               }
+                               zend_check_trait_usage(ce, cur_precedence->trait_method->ce TSRMLS_CC);
+
+                               /** Ensure that the prefered method is actually available. */
+                               lcname = zend_string_alloc(cur_method_ref->method_name->len, 0);
+                               zend_str_tolower_copy(lcname->val, 
+                                       cur_method_ref->method_name->val,
+                                       cur_method_ref->method_name->len);
+                               method_exists = zend_hash_exists(&cur_method_ref->ce->function_table,
+                                                                                                lcname);
+                               zend_string_free(lcname);
+                               if (!method_exists) {
+                                       zend_error_noreturn(E_COMPILE_ERROR,
+                                                          "A precedence rule was defined for %s::%s but this method does not exist",
+                                                          cur_method_ref->ce->name->val,
+                                                          cur_method_ref->method_name->val);
+                               }
+
+                               /** With the other traits, we are more permissive.
+                                       We do not give errors for those. This allows to be more
+                                       defensive in such definitions.
+                                       However, we want to make sure that the insteadof declaration
+                                       is consistent in itself.
+                                */
+                               j = 0;
+                               while (cur_precedence->exclude_from_classes[j].class_name) {
+                                       zend_string* class_name = cur_precedence->exclude_from_classes[j].class_name;
+
+                                       if (!(cur_precedence->exclude_from_classes[j].ce = zend_fetch_class(class_name, ZEND_FETCH_CLASS_TRAIT |ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC))) {
+                                               zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", class_name->val);
+                                       }
+                                       zend_check_trait_usage(ce, cur_precedence->exclude_from_classes[j].ce 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].ce) {
+                                               zend_error_noreturn(E_COMPILE_ERROR,
+                                                                  "Inconsistent insteadof definition. "
+                                                                  "The method %s is to be used from %s, but %s is also on the exclude list",
+                                                                  cur_method_ref->method_name->val,
+                                                                  cur_precedence->trait_method->ce->name->val,
+                                                                  cur_precedence->trait_method->ce->name->val);
+                                       }
+
+                                       zend_string_release(class_name);
+                                       j++;
+                               }
+                       }
+                       i++;
+               }
+       }
+
+       if (ce->trait_aliases) {
+               i = 0;
+               while (ce->trait_aliases[i]) {
+                       /** For all aliases with an explicit class name, resolve the class now. */
+                       if (ce->trait_aliases[i]->trait_method->class_name) {
+                               cur_method_ref = ce->trait_aliases[i]->trait_method;
+                               if (!(cur_method_ref->ce = zend_fetch_class(cur_method_ref->class_name, ZEND_FETCH_CLASS_TRAIT|ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC))) {
+                                       zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", cur_method_ref->class_name->val);
+                               }
+                               zend_check_trait_usage(ce, cur_method_ref->ce TSRMLS_CC);
+
+                               /** And, ensure that the referenced method is resolvable, too. */
+                               lcname = zend_string_alloc(cur_method_ref->method_name->len, 0);
+                               zend_str_tolower_copy(lcname->val,
+                                       cur_method_ref->method_name->val,
+                                       cur_method_ref->method_name->len);
+                               method_exists = zend_hash_exists(&cur_method_ref->ce->function_table,
+                                               lcname);
+                               zend_string_free(lcname);
+
+                               if (!method_exists) {
+                                       zend_error_noreturn(E_COMPILE_ERROR, "An alias was defined for %s::%s but this method does not exist", cur_method_ref->ce->name->val, cur_method_ref->method_name->val);
+                               }
+                       }
+                       i++;
+               }
+       }
+}
+/* }}} */
+
+static void zend_traits_compile_exclude_table(HashTable* exclude_table, zend_trait_precedence **precedences, zend_class_entry *trait) /* {{{ */
+{
+       size_t i = 0, j;
+
+       if (!precedences) {
+               return;
+       }
+       while (precedences[i]) {
+               if (precedences[i]->exclude_from_classes) {
+                       j = 0;
+                       while (precedences[i]->exclude_from_classes[j].ce) {
+                               if (precedences[i]->exclude_from_classes[j].ce == trait) {
+                                       zend_string *lcname = zend_string_alloc(precedences[i]->trait_method->method_name->len, 0);
+                                                                               
+                                       zend_str_tolower_copy(lcname->val,
+                                               precedences[i]->trait_method->method_name->val,
+                                               precedences[i]->trait_method->method_name->len);
+                                       if (zend_hash_add_empty_element(exclude_table, lcname) == NULL) {
+                                               zend_string_release(lcname);
+                                               zend_error_noreturn(E_COMPILE_ERROR, "Failed to evaluate a trait precedence (%s). Method of trait %s was defined to be excluded multiple times", precedences[i]->trait_method->method_name->val, trait->name->val);
+                                       }
+                                       zend_string_release(lcname);
+                               }
+                               ++j;
+                       }
+               }
+               ++i;
+       }
+}
+/* }}} */
+
+static void zend_do_traits_method_binding(zend_class_entry *ce TSRMLS_DC) /* {{{ */
+{
+       uint32_t i;
+       HashTable *overriden = NULL;
+       zend_string *key;
+       zend_function *fn;
+
+       for (i = 0; i < ce->num_traits; i++) {
+               if (ce->trait_precedences) {
+                       HashTable exclude_table;
+
+                       /* TODO: revisit this start size, may be its not optimal */
+                       zend_hash_init_ex(&exclude_table, 8, 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_HASH_FOREACH_STR_KEY_PTR(&ce->traits[i]->function_table, key, fn) {
+                               zend_traits_copy_functions(key, fn, ce, &overriden, &exclude_table TSRMLS_CC);
+                       } ZEND_HASH_FOREACH_END();
+
+                       zend_hash_destroy(&exclude_table);
+               } else {
+                       ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->traits[i]->function_table, key, fn) {
+                               zend_traits_copy_functions(key, fn, ce, &overriden, NULL TSRMLS_CC);
+                       } ZEND_HASH_FOREACH_END();
+               }
+       }
+
+       ZEND_HASH_FOREACH_PTR(&ce->function_table, fn) {
+               zend_fixup_trait_method(fn, ce);
+       } ZEND_HASH_FOREACH_END();
+
+       if (overriden) {
+               zend_hash_destroy(overriden);
+               FREE_HASHTABLE(overriden);
+       }
+}
+/* }}} */
+
+static zend_class_entry* find_first_definition(zend_class_entry *ce, size_t current_trait, zend_string *prop_name, zend_class_entry *coliding_ce) /* {{{ */
+{
+       size_t i;
+
+       if (coliding_ce == ce) {
+               for (i = 0; i < current_trait; i++) {
+                       if (zend_hash_exists(&ce->traits[i]->properties_info, prop_name)) {
+                               return ce->traits[i];
+                       }
+               }
+       }
+
+       return coliding_ce;
+}
+/* }}} */
+
+static void zend_do_traits_property_binding(zend_class_entry *ce TSRMLS_DC) /* {{{ */
+{
+       size_t i;
+       zend_property_info *property_info;
+       zend_property_info *coliding_prop;
+       zval compare_result;
+       zend_string* prop_name;
+       const char* class_name_unused;
+       zend_bool not_compatible;
+       zval* prop_value;
+       uint32_t flags;
+       zend_string *doc_comment;
+
+       /* 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
+        * - if compatible, then strict notice
+        */
+       for (i = 0; i < ce->num_traits; i++) {
+               ZEND_HASH_FOREACH_PTR(&ce->traits[i]->properties_info, property_info) {
+                       /* first get the unmangeld name if necessary,
+                        * then check whether the property is already there
+                        */
+                       flags = property_info->flags;
+                       if ((flags & ZEND_ACC_PPP_MASK) == ZEND_ACC_PUBLIC) {
+                               prop_name = zend_string_copy(property_info->name);
+                       } else {
+                               const char *pname;
+                               size_t pname_len;
+
+                               /* for private and protected we need to unmangle the names */
+                               zend_unmangle_property_name_ex(property_info->name,
+                                                                                       &class_name_unused, &pname, &pname_len);
+                               prop_name = zend_string_init(pname, pname_len, 0);
+                       }
+
+                       /* next: check for conflicts with current class */
+                       if ((coliding_prop = zend_hash_find_ptr(&ce->properties_info, prop_name)) != NULL) {
+                               if (coliding_prop->flags & ZEND_ACC_SHADOW) {
+                                       zend_hash_del(&ce->properties_info, prop_name);
+                                       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 {
+                                                       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);
+                                               }
+                                       } else {
+                                               /* the flags are not identical, thus, we assume properties are not compatible */
+                                               not_compatible = 1;
+                                       }
+
+                                       if (not_compatible) {
+                                               zend_error_noreturn(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, coliding_prop->ce)->name->val,
+                                                               property_info->ce->name->val,
+                                                               prop_name->val,
+                                                               ce->name->val);
+                                       } 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, coliding_prop->ce)->name->val,
+                                                               property_info->ce->name->val,
+                                                               prop_name->val,
+                                                               ce->name->val);
+                                               zend_string_release(prop_name);
+                                               continue;
+                                       }
+                               }
+                       }
+
+                       /* property not found, so lets add it */
+                       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];
+                       }
+                       if (Z_REFCOUNTED_P(prop_value)) Z_ADDREF_P(prop_value);
+
+                       doc_comment = property_info->doc_comment ? zend_string_copy(property_info->doc_comment) : NULL;
+                       zend_declare_property_ex(ce, prop_name,
+                                                                        prop_value, flags,
+                                                                    doc_comment TSRMLS_CC);
+                       zend_string_release(prop_name);
+               } ZEND_HASH_FOREACH_END();
+       }
+}
+/* }}} */
+
+static void zend_do_check_for_inconsistent_traits_aliasing(zend_class_entry *ce TSRMLS_DC) /* {{{ */
+{
+       int i = 0;
+       zend_trait_alias* cur_alias;
+       zend_string* lc_method_name;
+
+       if (ce->trait_aliases) {
+               while (ce->trait_aliases[i]) {
+                       cur_alias = ce->trait_aliases[i];
+                       /** The trait for this alias has not been resolved, this means, this
+                               alias was not applied. Abort with an error. */
+                       if (!cur_alias->trait_method->ce) {
+                               if (cur_alias->alias) {
+                                       /** Plain old inconsistency/typo/bug */
+                                       zend_error_noreturn(E_COMPILE_ERROR,
+                                                          "An alias (%s) was defined for method %s(), but this method does not exist",
+                                                          cur_alias->alias->val,
+                                                          cur_alias->trait_method->method_name->val);
+                               } else {
+                                       /** Here are two possible cases:
+                                               1) this is an attempt to modifiy the visibility
+                                                  of a method introduce as part of another alias.
+                                                  Since that seems to violate the DRY principle,
+                                                  we check against it and abort.
+                                               2) it is just a plain old inconsitency/typo/bug
+                                                  as in the case where alias is set. */
+
+                                       lc_method_name = zend_string_alloc(cur_alias->trait_method->method_name->len, 0);
+                                       zend_str_tolower_copy(
+                                               lc_method_name->val,
+                                               cur_alias->trait_method->method_name->val,
+                                               cur_alias->trait_method->method_name->len);
+                                       if (zend_hash_exists(&ce->function_table,
+                                                                                lc_method_name)) {
+                                               zend_string_free(lc_method_name);
+                                               zend_error_noreturn(E_COMPILE_ERROR,
+                                                                  "The modifiers for the trait alias %s() need to be changed in the same statment in which the alias is defined. Error",
+                                                                  cur_alias->trait_method->method_name->val);
+                                       } else {
+                                               zend_string_free(lc_method_name);
+                                               zend_error_noreturn(E_COMPILE_ERROR,
+                                                                  "The modifiers of the trait method %s() are changed, but this method does not exist. Error",
+                                                                  cur_alias->trait_method->method_name->val);
+
+                                       }
+                               }
+                       }
+                       i++;
+               }
+       }
+}
+/* }}} */
+
+ZEND_API void zend_do_bind_traits(zend_class_entry *ce TSRMLS_DC) /* {{{ */
+{
+
+       if (ce->num_traits <= 0) {
+               return;
+       }
+
+       /* complete initialization of trait strutures in ce */
+       zend_traits_init_trait_structures(ce TSRMLS_CC);
+
+       /* first care about all methods to be flattened into the class */
+       zend_do_traits_method_binding(ce TSRMLS_CC);
+
+       /* Aliases which have not been applied indicate typos/bugs. */
+       zend_do_check_for_inconsistent_traits_aliasing(ce TSRMLS_CC);
+
+       /* then flatten the properties into it, to, mostly to notfiy developer about problems */
+       zend_do_traits_property_binding(ce TSRMLS_CC);
+
+       /* verify that all abstract methods from traits have been implemented */
+       zend_verify_abstract_class(ce TSRMLS_CC);
+
+       /* now everything should be fine and an added ZEND_ACC_IMPLICIT_ABSTRACT_CLASS should be removed */
+       if (ce->ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) {
+               ce->ce_flags -= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
+       }
+}
+/* }}} */
+
diff --git a/Zend/zend_inheritance.h b/Zend/zend_inheritance.h
new file mode 100644 (file)
index 0000000..9cc4320
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+   +----------------------------------------------------------------------+
+   | Zend Engine                                                          |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1998-2014 Zend Technologies Ltd. (http://www.zend.com) |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 2.00 of the Zend license,     |
+   | that is bundled with this package in the file LICENSE, and is        |
+   | available through the world-wide-web at the following url:           |
+   | http://www.zend.com/license/2_00.txt.                                |
+   | If you did not receive a copy of the Zend license and are unable to  |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@zend.com so we can mail you a copy immediately.              |
+   +----------------------------------------------------------------------+
+   | Authors: Andi Gutmans <andi@zend.com>                                |
+   |          Zeev Suraski <zeev@zend.com>                                |
+   +----------------------------------------------------------------------+
+*/
+
+#ifndef ZEND_INHERITANCE_H
+#define ZEND_INHERITANCE_H
+
+#include "zend.h"
+
+BEGIN_EXTERN_C()
+
+ZEND_API void zend_do_inherit_interfaces(zend_class_entry *ce, const zend_class_entry *iface TSRMLS_DC);
+ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry *iface 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);
+
+ZEND_API void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent_ce TSRMLS_DC);
+void zend_do_early_binding(TSRMLS_D);
+
+END_EXTERN_C()
+
+#endif
+
index 428c574bf855bd0f18d7b98ff7e676a1ef1b5690..616fc502a412498100499a246ed99b1e9e80f101 100644 (file)
@@ -1490,11 +1490,8 @@ PHP_ADD_SOURCES(Zend, \
     zend_ini.c zend_qsort.c zend_multibyte.c zend_ts_hash.c zend_stream.c \
     zend_iterators.c zend_interfaces.c zend_exceptions.c zend_strtod.c zend_gc.c \
     zend_closures.c zend_float.c zend_string.c zend_signal.c zend_generators.c \
-    zend_virtual_cwd.c zend_ast.c)
-
-if test -r "$abs_srcdir/Zend/zend_objects.c"; then
-  PHP_ADD_SOURCES(Zend, zend_objects.c zend_object_handlers.c zend_objects_API.c zend_default_classes.c)
-fi
+    zend_virtual_cwd.c zend_ast.c zend_objects.c zend_object_handlers.c zend_objects_API.c \
+    zend_default_classes.c zend_inheritance.c)
 
 dnl Selectively disable optimization due to high RAM usage during
 dnl compiling the executor.