Diff for /embedaddon/php/Zend/zend_compile.c between versions 1.1.1.2 and 1.1.1.3

version 1.1.1.2, 2012/05/29 12:34:35 version 1.1.1.3, 2013/07/22 01:32:15
Line 2 Line 2
    +----------------------------------------------------------------------+     +----------------------------------------------------------------------+
    | Zend Engine                                                          |     | Zend Engine                                                          |
    +----------------------------------------------------------------------+     +----------------------------------------------------------------------+
   | Copyright (c) 1998-2012 Zend Technologies Ltd. (http://www.zend.com) |   | Copyright (c) 1998-2013 Zend Technologies Ltd. (http://www.zend.com) |
    +----------------------------------------------------------------------+     +----------------------------------------------------------------------+
    | This source file is subject to version 2.00 of the Zend license,     |     | 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        |      | that is bundled with this package in the file LICENSE, and is        | 
Line 219  ZEND_API void file_handle_dtor(zend_file_handle *fh) / Line 219  ZEND_API void file_handle_dtor(zend_file_handle *fh) /
 void init_compiler(TSRMLS_D) /* {{{ */  void init_compiler(TSRMLS_D) /* {{{ */
 {  {
         CG(active_op_array) = NULL;          CG(active_op_array) = NULL;
           memset(&CG(context), 0, sizeof(CG(context)));
         zend_init_compiler_data_structures(TSRMLS_C);          zend_init_compiler_data_structures(TSRMLS_C);
         zend_init_rsrc_list(TSRMLS_C);          zend_init_rsrc_list(TSRMLS_C);
         zend_hash_init(&CG(filenames_table), 5, NULL, (dtor_func_t) free_estring, 0);          zend_hash_init(&CG(filenames_table), 5, NULL, (dtor_func_t) free_estring, 0);
Line 1685  void zend_do_begin_function_declaration(znode *functio Line 1686  void zend_do_begin_function_declaration(znode *functio
                 zval key;                  zval key;
   
                 if (CG(current_namespace)) {                  if (CG(current_namespace)) {
                        /* Prefix function name with current namespcae name */                        /* Prefix function name with current namespace name */
                         znode tmp;                          znode tmp;
   
                         tmp.u.constant = *CG(current_namespace);                          tmp.u.constant = *CG(current_namespace);
Line 1797  void zend_do_end_function_declaration(const znode *fun Line 1798  void zend_do_end_function_declaration(const znode *fun
         zend_do_return(NULL, 0 TSRMLS_CC);          zend_do_return(NULL, 0 TSRMLS_CC);
   
         pass_two(CG(active_op_array) TSRMLS_CC);          pass_two(CG(active_op_array) TSRMLS_CC);
        zend_release_labels(TSRMLS_C);        zend_release_labels(0 TSRMLS_CC);
   
         if (CG(active_class_entry)) {          if (CG(active_class_entry)) {
                 zend_check_magic_method_implementation(CG(active_class_entry), (zend_function*)CG(active_op_array), E_COMPILE_ERROR TSRMLS_CC);                  zend_check_magic_method_implementation(CG(active_class_entry), (zend_function*)CG(active_op_array), E_COMPILE_ERROR TSRMLS_CC);
Line 2319  void zend_do_goto(const znode *label TSRMLS_DC) /* {{{ Line 2320  void zend_do_goto(const znode *label TSRMLS_DC) /* {{{
 }  }
 /* }}} */  /* }}} */
   
void zend_release_labels(TSRMLS_D) /* {{{ */void zend_release_labels(int temporary TSRMLS_DC) /* {{{ */
 {  {
         if (CG(context).labels) {          if (CG(context).labels) {
                 zend_hash_destroy(CG(context).labels);                  zend_hash_destroy(CG(context).labels);
                 FREE_HASHTABLE(CG(context).labels);                  FREE_HASHTABLE(CG(context).labels);
                   CG(context).labels = NULL;
         }          }
        if (!zend_stack_is_empty(&CG(context_stack))) {        if (!temporary && !zend_stack_is_empty(&CG(context_stack))) {
                 zend_compiler_context *ctx;                  zend_compiler_context *ctx;
   
                 zend_stack_top(&CG(context_stack), (void**)&ctx);                  zend_stack_top(&CG(context_stack), (void**)&ctx);
Line 2935  static zend_bool zend_do_perform_implementation_check( Line 2937  static zend_bool zend_do_perform_implementation_check(
                 return 1;                  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 */          /* check number of arguments */
         if (proto->common.required_num_args < fe->common.required_num_args          if (proto->common.required_num_args < fe->common.required_num_args
                 || proto->common.num_args > fe->common.num_args) {                  || proto->common.num_args > fe->common.num_args) {
Line 3264  static void do_inheritance_check_on_method(zend_functi Line 3271  static void do_inheritance_check_on_method(zend_functi
                 }                  }
         } else if (EG(error_reporting) & E_STRICT || EG(user_error_handler)) { /* Check E_STRICT (or custom error handler) before the check so that we save some time */          } else if (EG(error_reporting) & E_STRICT || EG(user_error_handler)) { /* 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)) {                  if (!zend_do_perform_implementation_check(child, parent TSRMLS_CC)) {
                        char *method_prototype = zend_get_function_declaration(child->common.prototype 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, method_prototype);                           zend_error(E_STRICT, "Declaration of %s::%s() should be compatible with %s", ZEND_FN_SCOPE_NAME(child), child->common.function_name, method_prototype); 
                         efree(method_prototype);                          efree(method_prototype);
                 }                  }
Line 3327  static zend_bool do_inherit_property_access_check(Hash Line 3334  static zend_bool do_inherit_property_access_check(Hash
                 if ((child_info->flags & ZEND_ACC_PPP_MASK) > (parent_info->flags & ZEND_ACC_PPP_MASK)) {                  if ((child_info->flags & ZEND_ACC_PPP_MASK) > (parent_info->flags & ZEND_ACC_PPP_MASK)) {
                         zend_error(E_COMPILE_ERROR, "Access level to %s::$%s must be %s (as in class %s)%s", ce->name, hash_key->arKey, zend_visibility_string(parent_info->flags), parent_ce->name, (parent_info->flags&ZEND_ACC_PUBLIC) ? "" : " or weaker");                          zend_error(E_COMPILE_ERROR, "Access level to %s::$%s must be %s (as in class %s)%s", ce->name, hash_key->arKey, zend_visibility_string(parent_info->flags), parent_ce->name, (parent_info->flags&ZEND_ACC_PUBLIC) ? "" : " or weaker");
                 } else if ((child_info->flags & ZEND_ACC_STATIC) == 0) {                  } else if ((child_info->flags & ZEND_ACC_STATIC) == 0) {
                        Z_DELREF_P(ce->default_properties_table[parent_info->offset]);                        zval_ptr_dtor(&(ce->default_properties_table[parent_info->offset]));
                         ce->default_properties_table[parent_info->offset] = ce->default_properties_table[child_info->offset];                          ce->default_properties_table[parent_info->offset] = ce->default_properties_table[child_info->offset];
                         ce->default_properties_table[child_info->offset] = NULL;                          ce->default_properties_table[child_info->offset] = NULL;
                         child_info->offset = parent_info->offset;                          child_info->offset = parent_info->offset;
Line 3521  ZEND_API void zend_do_inheritance(zend_class_entry *ce Line 3528  ZEND_API void zend_do_inheritance(zend_class_entry *ce
   
         if (ce->ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS && ce->type == ZEND_INTERNAL_CLASS) {          if (ce->ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS && ce->type == ZEND_INTERNAL_CLASS) {
                 ce->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS;                  ce->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS;
        } else if (!(ce->ce_flags & ZEND_ACC_IMPLEMENT_INTERFACES)        } else if (!(ce->ce_flags & (ZEND_ACC_IMPLEMENT_INTERFACES|ZEND_ACC_IMPLEMENT_TRAITS))) {
                                && !(ce->ce_flags & ZEND_ACC_IMPLEMENT_TRAITS)) { 
                 /* The verification will be done in runtime by ZEND_VERIFY_ABSTRACT_CLASS */                  /* The verification will be done in runtime by ZEND_VERIFY_ABSTRACT_CLASS */
                 zend_verify_abstract_class(ce TSRMLS_CC);                  zend_verify_abstract_class(ce TSRMLS_CC);
         }          }
Line 3629  static zend_bool zend_traits_method_compatibility_chec Line 3635  static zend_bool zend_traits_method_compatibility_chec
         zend_uint other_flags = other_fn->common.scope->ce_flags;          zend_uint other_flags = other_fn->common.scope->ce_flags;
                   
         return zend_do_perform_implementation_check(fn, other_fn TSRMLS_CC)          return zend_do_perform_implementation_check(fn, other_fn TSRMLS_CC)
                && zend_do_perform_implementation_check(other_fn, 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) == (other_flags & ZEND_ACC_FINAL))   /* equal final qualifier */                && ((fn_flags & (ZEND_ACC_FINAL|ZEND_ACC_STATIC)) == 
                && ((fn_flags & ZEND_ACC_STATIC)== (other_flags & ZEND_ACC_STATIC)); /* equal static qualifier */                    (other_flags & (ZEND_ACC_FINAL|ZEND_ACC_STATIC))); /* equal final and static qualifier */
 }  }
 /* }}} */  /* }}} */
   
 static int zend_traits_merge_functions(zend_function *fn TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */  
 {  
         size_t current;  
         size_t i;  
         size_t count;  
         HashTable* resulting_table;  
         HashTable** function_tables;  
         zend_class_entry *ce;  
         size_t collision = 0;  
         size_t abstract_solved = 0;  
         zend_function* other_trait_fn;  
   
         current                 = va_arg(args, size_t);  /* index of current trait */  
         count                   = va_arg(args, size_t);  
         resulting_table = va_arg(args, HashTable*);  
         function_tables = va_arg(args, HashTable**);  
         ce                              = va_arg(args, zend_class_entry*);  
   
         for (i = 0; i < count; i++) {  
                 if (i == current) {  
                         continue; /* just skip this, cause its the table this function is applied on */  
                 }  
                   
                 if (zend_hash_quick_find(function_tables[i], hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void **)&other_trait_fn) == SUCCESS) {  
                         /* if it is an abstract method, there is no collision */  
                         if (other_trait_fn->common.fn_flags & ZEND_ACC_ABSTRACT) {  
                                 /* Make sure they are compatible */  
                                 /* In case both are abstract, just check prototype, but need to do that in both directions */  
                                 if (!zend_traits_method_compatibility_check(fn, other_trait_fn TSRMLS_CC)) {  
                                         zend_error(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",  
                                                                                                 zend_get_function_declaration(fn TSRMLS_CC),  
                                                                                                 zend_get_function_declaration(other_trait_fn TSRMLS_CC));  
                                 }  
                                   
                                 /* we can savely free and remove it from other table */  
                                 zend_function_dtor(other_trait_fn);  
                                 zend_hash_quick_del(function_tables[i], hash_key->arKey, hash_key->nKeyLength, hash_key->h);  
                         } else {  
                                 /* if it is not an abstract method, there is still no collision */  
                                 /* if fn is an abstract method */  
                                 if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {  
                                         /* Make sure they are compatible.  
                                            Here, we already know other_trait_fn cannot be abstract, full check ok. */  
                                         if (!zend_traits_method_compatibility_check(fn, other_trait_fn TSRMLS_CC)) {  
                                                 zend_error(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",  
                                                                                                         zend_get_function_declaration(fn TSRMLS_CC),  
                                                                                                         zend_get_function_declaration(other_trait_fn TSRMLS_CC));  
                                         }  
                                           
                                         /* just mark as solved, will be added if its own trait is processed */  
                                         abstract_solved = 1;  
                                 } else {  
                                         /* but else, we have a collision of non-abstract methods */  
                                         collision++;  
                                         zend_function_dtor(other_trait_fn);  
                                         zend_hash_quick_del(function_tables[i], hash_key->arKey, hash_key->nKeyLength, hash_key->h);  
                                 }  
                         }  
                 }  
         }  
   
         if (collision) {  
                 zend_function* class_fn;  
   
                 /* make sure method is not already overridden in class */  
                 if (zend_hash_quick_find(&ce->function_table, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void **)&class_fn) == FAILURE  
                         || class_fn->common.scope != ce) {  
                         zend_error(E_COMPILE_ERROR, "Trait method %s has not been applied, because there are collisions with other trait methods on %s", fn->common.function_name, ce->name);  
                 }  
   
                 zend_function_dtor(fn);  
         } else if (abstract_solved) {  
                 zend_function_dtor(fn);  
         } else {  
                 /* Add it to result function table */  
                 if (zend_hash_quick_add(resulting_table, hash_key->arKey, hash_key->nKeyLength, hash_key->h, fn, sizeof(zend_function), NULL)==FAILURE) {  
                         zend_error(E_COMPILE_ERROR, "Trait method %s has not been applied, because failure occured during updating resulting trait method table", fn->common.function_name);  
                 }  
         }  
   
         return ZEND_HASH_APPLY_REMOVE;  
 }  
 /* }}} */  
   
 static void zend_add_magic_methods(zend_class_entry* ce, const char* mname, uint mname_len, zend_function* fe TSRMLS_DC) /* {{{ */  static void zend_add_magic_methods(zend_class_entry* ce, const char* mname, uint mname_len, zend_function* fe TSRMLS_DC) /* {{{ */
 {  {
         if (!strncmp(mname, ZEND_CLONE_FUNC_NAME, mname_len)) {          if (!strncmp(mname, ZEND_CLONE_FUNC_NAME, mname_len)) {
Line 3760  static void zend_add_magic_methods(zend_class_entry* c Line 3682  static void zend_add_magic_methods(zend_class_entry* c
 }  }
 /* }}} */  /* }}} */
   
static int zend_traits_merge_functions_to_class(zend_function *fn TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */static void zend_add_trait_method(zend_class_entry *ce, const char *name, const char *arKey, uint nKeyLength, zend_function *fn, HashTable **overriden TSRMLS_DC) /* {{{ */
 {  {
        zend_class_entry *ce = va_arg(args, zend_class_entry*);        zend_function *existing_fn = NULL;
        zend_function* existing_fn = NULL;        ulong h = zend_hash_func(arKey, nKeyLength);
        zend_function fn_copy, *fn_copy_p; 
        zend_function* prototype = NULL;  /* is used to determine the prototype according to the inheritance chain */ 
   
        if (zend_hash_quick_find(&ce->function_table, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void**) &existing_fn) == FAILURE ||        if (zend_hash_quick_find(&ce->function_table, arKey, nKeyLength, h, (void**) &existing_fn) == SUCCESS) {
            existing_fn->common.scope != ce) {                if (existing_fn->common.scope == ce) {
                /* not found or inherited from other class or interface */                        /* members from the current class override trait methods */
                zend_function* parent_function;                        /* use temporary *overriden HashTable to detect hidden conflict */
                        if (*overriden) {
                if (ce->parent && zend_hash_quick_find(&ce->parent->function_table, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void**) &parent_function) != FAILURE) {                                if (zend_hash_quick_find(*overriden, arKey, nKeyLength, h, (void**) &existing_fn) == SUCCESS) {
                        prototype = parent_function; /* ->common.fn_flags |= ZEND_ACC_ABSTRACT; */                                        if (existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
                                                                        /* Make sure the trait method is compatible with previosly declared abstract method */
                        /* we got that method in the parent class, and are going to override it,                                                if (!zend_traits_method_compatibility_check(fn, existing_fn TSRMLS_CC)) {
                          except, if the trait is just asking to have an abstract method implemented. */                                                        zend_error(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
                        if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {                                                                zend_get_function_declaration(fn TSRMLS_CC),
                                /* then we clean up an skip this method */                                                                zend_get_function_declaration(existing_fn TSRMLS_CC));
                                zend_function_dtor(fn);                                                }
                                return ZEND_HASH_APPLY_REMOVE;                                        } else if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
                                                 /* Make sure the abstract declaration is compatible with previous declaration */
                                                 if (!zend_traits_method_compatibility_check(existing_fn, fn TSRMLS_CC)) {
                                                         zend_error(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
                                                                 zend_get_function_declaration(fn TSRMLS_CC),
                                                                 zend_get_function_declaration(existing_fn TSRMLS_CC));
                                                 }
                                                 return;
                                         }
                                 }
                         } else {
                                 ALLOC_HASHTABLE(*overriden);
                                 zend_hash_init_ex(*overriden, 2, NULL, NULL, 0, 0);
                         }                          }
                }                        zend_hash_quick_update(*overriden, arKey, nKeyLength, h, fn, sizeof(zend_function), (void**)&fn);
                        return;
                fn->common.scope = ce;                } else if (existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
                fn->common.prototype = prototype;                        /* Make sure the trait method is compatible with previosly declared abstract method */
                        if (!zend_traits_method_compatibility_check(fn, existing_fn TSRMLS_CC)) {
                if (prototype                                zend_error(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
                        && (prototype->common.fn_flags & ZEND_ACC_IMPLEMENTED_ABSTRACT                                        zend_get_function_declaration(fn TSRMLS_CC),
                        || prototype->common.fn_flags & ZEND_ACC_ABSTRACT)) {                                        zend_get_function_declaration(existing_fn TSRMLS_CC));
                        fn->common.fn_flags |= ZEND_ACC_IMPLEMENTED_ABSTRACT;                        }
                } else if (fn->common.fn_flags & ZEND_ACC_IMPLEMENTED_ABSTRACT) {                } else if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
                        /* remove ZEND_ACC_IMPLEMENTED_ABSTRACT flag, think it shouldn't be copied to class */                        /* Make sure the abstract declaration is compatible with previous declaration */
                        fn->common.fn_flags = fn->common.fn_flags - ZEND_ACC_IMPLEMENTED_ABSTRACT;                        if (!zend_traits_method_compatibility_check(existing_fn, fn TSRMLS_CC)) {
                }                                zend_error(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
                                        zend_get_function_declaration(fn TSRMLS_CC),
                /* check whether the trait method fullfills the inheritance requirements */                                        zend_get_function_declaration(existing_fn TSRMLS_CC));
                if (prototype) {                        }
                        do_inheritance_check_on_method(fn, prototype TSRMLS_CC);                        return;
                }                } else if ((existing_fn->common.scope->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {
                /* one more thing: make sure we properly implement an abstract method */                        /* two trais can't define the same non-abstract method */
                if (existing_fn && existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT) {#if 1
                         zend_error(E_COMPILE_ERROR, "Trait method %s has not been applied, because there are collisions with other trait methods on %s",
                                 name, ce->name);
 #else           /* TODO: better errot message */
                         zend_error(E_COMPILE_ERROR, "Trait method %s::%s has not been applied as %s::%s, because of collision with %s::%s",
                                 fn->common.scope->name, fn->common.function_name,
                                 ce->name, name,
                                 existing_fn->common.scope->name, existing_fn->common.function_name);
 #endif
                 } else {
                         /* inherited members are overridden by members inserted by traits */
                         /* check whether the trait method fulfills the inheritance requirements */
                         do_inheritance_check_on_method(fn, existing_fn TSRMLS_CC);                          do_inheritance_check_on_method(fn, existing_fn TSRMLS_CC);
                 }                  }
           }
   
                /* delete inherited fn if the function to be added is not abstract */        function_add_ref(fn);
                if (existing_fn        zend_hash_quick_update(&ce->function_table, arKey, nKeyLength, h, fn, sizeof(zend_function), (void**)&fn);
                        && existing_fn->common.scope != ce        zend_add_magic_methods(ce, arKey, nKeyLength, fn TSRMLS_CC);
                        && (fn->common.fn_flags & ZEND_ACC_ABSTRACT) == 0) {}
                        /* it is just a reference which was added to the subclass while doing/* }}} */
                           the inheritance, so we can deleted now, and will add the overriding  
                           method afterwards. 
                           Except, if we try to add an abstract function, then we should not 
                           delete the inherited one */ 
                        zend_hash_quick_del(&ce->function_table, hash_key->arKey, hash_key->nKeyLength, hash_key->h); 
                } 
   
   static int zend_fixup_trait_method(zend_function *fn, zend_class_entry *ce TSRMLS_DC) /* {{{ */
   {
           if ((fn->common.scope->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {
   
                   fn->common.scope = ce;
   
                 if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {                  if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
                         ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;                          ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
                 }                  }
                 if (fn->op_array.static_variables) {                  if (fn->op_array.static_variables) {
                         ce->ce_flags |= ZEND_HAS_STATIC_IN_METHODS;                          ce->ce_flags |= ZEND_HAS_STATIC_IN_METHODS;
                 }                  }
                 fn_copy = *fn;  
                 function_add_ref(&fn_copy);  
   
                 if (zend_hash_quick_update(&ce->function_table, hash_key->arKey, hash_key->nKeyLength, hash_key->h, &fn_copy, sizeof(zend_function), (void**)&fn_copy_p)==FAILURE) {  
                         zend_error(E_COMPILE_ERROR, "Trait method %s has not been applied, because failure occured during updating class method table", hash_key->arKey);  
                 }  
      
                 zend_add_magic_methods(ce, hash_key->arKey, hash_key->nKeyLength, fn_copy_p TSRMLS_CC);  
      
                 zend_function_dtor(fn);  
         } else {  
                 zend_function_dtor(fn);  
         }          }
        return ZEND_HASH_APPLY_KEEP;
        return ZEND_HASH_APPLY_REMOVE; 
 }  }
 /* }}} */  /* }}} */
   
 static int zend_traits_copy_functions(zend_function *fn TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */  static int zend_traits_copy_functions(zend_function *fn TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */
 {  {
        HashTable* target;        zend_class_entry  *ce;
        zend_trait_alias** aliases;        HashTable         **overriden;
        HashTable* exclude_table;        zend_trait_alias  *alias, **alias_ptr;
        char* lcname;        HashTable         *exclude_table;
        unsigned int fnname_len;        char              *lcname;
        zend_function fn_copy;        unsigned int       fnname_len;
        void* dummy;        zend_function      fn_copy;
        size_t i = 0;        void              *dummy;
   
        target        = va_arg(args, HashTable*);        ce            = va_arg(args, zend_class_entry*);
        aliases       = va_arg(args, zend_trait_alias**);        overriden     = va_arg(args, HashTable**);
         exclude_table = va_arg(args, HashTable*);          exclude_table = va_arg(args, HashTable*);
           
           fnname_len = hash_key->nKeyLength - 1;
   
         fnname_len = strlen(fn->common.function_name);  
   
         /* apply aliases which are qualified with a class name, there should not be any ambiguity */          /* apply aliases which are qualified with a class name, there should not be any ambiguity */
        if (aliases) {        if (ce->trait_aliases) {
                while (aliases[i]) {                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 */                          /* Scope unset or equal to the function we compare to, and the alias applies to fn */
                        if (aliases[i]->alias != NULL                        if (alias->alias != NULL
                                && (!aliases[i]->trait_method->ce || fn->common.scope == aliases[i]->trait_method->ce)                                && (!alias->trait_method->ce || fn->common.scope == alias->trait_method->ce)
                                && aliases[i]->trait_method->mname_len == fnname_len                                && alias->trait_method->mname_len == fnname_len
                                && (zend_binary_strcasecmp(aliases[i]->trait_method->method_name, aliases[i]->trait_method->mname_len, fn->common.function_name, fnname_len) == 0)) {                                && (zend_binary_strcasecmp(alias->trait_method->method_name, alias->trait_method->mname_len, hash_key->arKey, fnname_len) == 0)) {
                                 fn_copy = *fn;                                  fn_copy = *fn;
                                 function_add_ref(&fn_copy);  
                                 /* this function_name is never destroyed, because its refcount  
                                    greater than 1, classes are always destoyed in reverse order  
                                    and trait is declared early than this class */  
                                 fn_copy.common.function_name = aliases[i]->alias;  
                                                                                   
                                 /* if it is 0, no modifieres has been changed */                                  /* if it is 0, no modifieres has been changed */
                                if (aliases[i]->modifiers) {                                 if (alias->modifiers) { 
                                        fn_copy.common.fn_flags = aliases[i]->modifiers;                                        fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags ^ (fn->common.fn_flags & ZEND_ACC_PPP_MASK));
                                        if (!(aliases[i]->modifiers & ZEND_ACC_PPP_MASK)) { 
                                                fn_copy.common.fn_flags |= ZEND_ACC_PUBLIC; 
                                        } 
                                        fn_copy.common.fn_flags |= fn->common.fn_flags ^ (fn->common.fn_flags & ZEND_ACC_PPP_MASK); 
                                 }                                  }
   
                                lcname = zend_str_tolower_dup(aliases[i]->alias, aliases[i]->alias_len);                                lcname = zend_str_tolower_dup(alias->alias, alias->alias_len);
                                zend_add_trait_method(ce, alias->alias, lcname, alias->alias_len+1, &fn_copy, overriden TSRMLS_CC);
                                if (zend_hash_add(target, lcname, aliases[i]->alias_len+1, &fn_copy, sizeof(zend_function), NULL)==FAILURE) { 
                                        zend_error(E_COMPILE_ERROR, "Failed to add aliased trait method (%s) to the trait table. There is probably already a trait method with the same name", fn_copy.common.function_name); 
                                } 
                                 efree(lcname);                                  efree(lcname);
   
                                /** Record the trait from which this alias was resolved. */                                /* Record the trait from which this alias was resolved. */
                                if (!aliases[i]->trait_method->ce) {                                if (!alias->trait_method->ce) {
                                        aliases[i]->trait_method->ce = fn->common.scope;                                        alias->trait_method->ce = fn->common.scope;
                                 }                                  }
                         }                          }
                        i++;                        alias_ptr++;
                         alias = *alias_ptr;
                 }                  }
         }          }
   
        lcname = zend_str_tolower_dup(fn->common.function_name, fnname_len);        lcname = hash_key->arKey;
   
         if (exclude_table == NULL || zend_hash_find(exclude_table, lcname, fnname_len, &dummy) == FAILURE) {          if (exclude_table == NULL || zend_hash_find(exclude_table, lcname, fnname_len, &dummy) == FAILURE) {
                 /* is not in hashtable, thus, function is not to be excluded */                  /* is not in hashtable, thus, function is not to be excluded */
                 fn_copy = *fn;                  fn_copy = *fn;
                 function_add_ref(&fn_copy);  
   
                /* apply aliases which are not qualified by a class name, or which have not                /* apply aliases which have not alias name, just setting visibility */
                 * alias name, just setting visibility */                if (ce->trait_aliases) {
                if (aliases) {                        alias_ptr = ce->trait_aliases;
                        i = 0;                        alias = *alias_ptr;
                        while (aliases[i]) {                        while (alias) {
                                 /* Scope unset or equal to the function we compare to, and the alias applies to fn */                                  /* Scope unset or equal to the function we compare to, and the alias applies to fn */
                                if (aliases[i]->alias == NULL && aliases[i]->modifiers != 0                                if (alias->alias == NULL && alias->modifiers != 0
                                        && (!aliases[i]->trait_method->ce || fn->common.scope == aliases[i]->trait_method->ce)                                        && (!alias->trait_method->ce || fn->common.scope == alias->trait_method->ce)
                                        && (aliases[i]->trait_method->mname_len == fnname_len)                                        && (alias->trait_method->mname_len == fnname_len)
                                        && (zend_binary_strcasecmp(aliases[i]->trait_method->method_name, aliases[i]->trait_method->mname_len, fn->common.function_name, fnname_len) == 0)) {                                        && (zend_binary_strcasecmp(alias->trait_method->method_name, alias->trait_method->mname_len, lcname, fnname_len) == 0)) {
                                        fn_copy.common.fn_flags = aliases[i]->modifiers; 
   
                                        if (!(aliases[i]->modifiers & ZEND_ACC_PPP_MASK)) {                                        fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags ^ (fn->common.fn_flags & ZEND_ACC_PPP_MASK));
                                                fn_copy.common.fn_flags |= ZEND_ACC_PUBLIC; 
                                        } 
                                        fn_copy.common.fn_flags |= fn->common.fn_flags ^ (fn->common.fn_flags & ZEND_ACC_PPP_MASK); 
   
                                         /** Record the trait from which this alias was resolved. */                                          /** Record the trait from which this alias was resolved. */
                                        if (!aliases[i]->trait_method->ce) {                                        if (!alias->trait_method->ce) {
                                                aliases[i]->trait_method->ce = fn->common.scope;                                                alias->trait_method->ce = fn->common.scope;
                                         }                                          }
                                 }                                  }
                                i++;                                alias_ptr++;
                                 alias = *alias_ptr;
                         }                          }
                 }                  }
   
                if (zend_hash_add(target, lcname, fnname_len+1, &fn_copy, sizeof(zend_function), NULL)==FAILURE) {                zend_add_trait_method(ce, fn->common.function_name, lcname, fnname_len+1, &fn_copy, overriden TSRMLS_CC);
                        zend_error(E_COMPILE_ERROR, "Failed to add trait method (%s) to the trait table. There is probably already a trait method with the same name", fn_copy.common.function_name); 
                } 
         }          }
   
         efree(lcname);  
   
         return ZEND_HASH_APPLY_KEEP;          return ZEND_HASH_APPLY_KEEP;
 }  }
 /* }}} */  /* }}} */
   
/* Copies function table entries to target function table with applied aliasing */static void zend_check_trait_usage(zend_class_entry *ce, zend_class_entry *trait TSRMLS_DC) /* {{{ */
static void zend_traits_copy_trait_function_table(HashTable *target, HashTable *source, zend_trait_alias** aliases, HashTable* exclude_table TSRMLS_DC) /* {{{ */ 
 {  {
        zend_hash_apply_with_arguments(source TSRMLS_CC, (apply_func_args_t)zend_traits_copy_functions, 3, target, aliases, exclude_table);        zend_uint i;
 
         if ((trait->ce_flags & ZEND_ACC_TRAIT) != ZEND_ACC_TRAIT) {
                 zend_error(E_COMPILE_ERROR, "Class %s is not a trait, Only traits may be used in 'as' and 'insteadof' statements", trait->name);
         }
 
         for (i = 0; i < ce->num_traits; i++) {
                 if (ce->traits[i] == trait) {
                         return;
                 }
         }
         zend_error(E_COMPILE_ERROR, "Required Trait %s wasn't added to %s", trait->name, ce->name);
 }  }
 /* }}} */  /* }}} */
   
Line 3965  static void zend_traits_init_trait_structures(zend_cla Line 3888  static void zend_traits_init_trait_structures(zend_cla
                         /** Resolve classes for all precedence operations. */                          /** Resolve classes for all precedence operations. */
                         if (cur_precedence->exclude_from_classes) {                          if (cur_precedence->exclude_from_classes) {
                                 cur_method_ref = cur_precedence->trait_method;                                  cur_method_ref = cur_precedence->trait_method;
                                cur_precedence->trait_method->ce = zend_fetch_class(cur_method_ref->class_name,                                if (!(cur_precedence->trait_method->ce = zend_fetch_class(cur_method_ref->class_name, cur_method_ref->cname_len,
                                                                                                                                        cur_method_ref->cname_len, ZEND_FETCH_CLASS_TRAIT TSRMLS_CC);                                                                ZEND_FETCH_CLASS_TRAIT|ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC))) {
                                         zend_error(E_COMPILE_ERROR, "Could not find trait %s", cur_method_ref->class_name);
                                 }
                                 zend_check_trait_usage(ce, cur_precedence->trait_method->ce TSRMLS_CC);
   
                                 /** Ensure that the prefered method is actually available. */                                  /** Ensure that the prefered method is actually available. */
                                 lcname = zend_str_tolower_dup(cur_method_ref->method_name,                                  lcname = zend_str_tolower_dup(cur_method_ref->method_name,
Line 3993  static void zend_traits_init_trait_structures(zend_cla Line 3919  static void zend_traits_init_trait_structures(zend_cla
                                         char* class_name = (char*)cur_precedence->exclude_from_classes[j];                                          char* class_name = (char*)cur_precedence->exclude_from_classes[j];
                                         zend_uint name_length = strlen(class_name);                                          zend_uint name_length = strlen(class_name);
   
                                        cur_precedence->exclude_from_classes[j] = zend_fetch_class(class_name, name_length, ZEND_FETCH_CLASS_TRAIT TSRMLS_CC);                                        if (!(cur_precedence->exclude_from_classes[j] = zend_fetch_class(class_name, name_length, ZEND_FETCH_CLASS_TRAIT |ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC))) {
                                                                                        zend_error(E_COMPILE_ERROR, "Could not find trait %s", class_name);
                                         }                                       
                                         zend_check_trait_usage(ce, cur_precedence->exclude_from_classes[j] TSRMLS_CC);
 
                                         /* make sure that the trait method is not from a class mentioned in                                          /* make sure that the trait method is not from a class mentioned in
                                          exclude_from_classes, for consistency */                                           exclude_from_classes, for consistency */
                                         if (cur_precedence->trait_method->ce == cur_precedence->exclude_from_classes[i]) {                                          if (cur_precedence->trait_method->ce == cur_precedence->exclude_from_classes[i]) {
Line 4020  static void zend_traits_init_trait_structures(zend_cla Line 3949  static void zend_traits_init_trait_structures(zend_cla
                         /** For all aliases with an explicit class name, resolve the class now. */                          /** For all aliases with an explicit class name, resolve the class now. */
                         if (ce->trait_aliases[i]->trait_method->class_name) {                          if (ce->trait_aliases[i]->trait_method->class_name) {
                                 cur_method_ref = ce->trait_aliases[i]->trait_method;                                  cur_method_ref = ce->trait_aliases[i]->trait_method;
                                cur_method_ref->ce = zend_fetch_class(cur_method_ref->class_name, cur_method_ref->cname_len, ZEND_FETCH_CLASS_TRAIT TSRMLS_CC);                                if (!(cur_method_ref->ce = zend_fetch_class(cur_method_ref->class_name, cur_method_ref->cname_len, ZEND_FETCH_CLASS_TRAIT|ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC))) {
                                         zend_error(E_COMPILE_ERROR, "Could not find trait %s", cur_method_ref->class_name);
                                 }
                                 zend_check_trait_usage(ce, cur_method_ref->ce TSRMLS_CC);
   
                                 /** And, ensure that the referenced method is resolvable, too. */                                  /** And, ensure that the referenced method is resolvable, too. */
                                 lcname = zend_str_tolower_dup(cur_method_ref->method_name,                                  lcname = zend_str_tolower_dup(cur_method_ref->method_name,
                                      cur_method_ref->mname_len);                                                cur_method_ref->mname_len);
                                 method_exists = zend_hash_exists(&cur_method_ref->ce->function_table,                                  method_exists = zend_hash_exists(&cur_method_ref->ce->function_table,
                                         lcname, cur_method_ref->mname_len + 1);                                                lcname, cur_method_ref->mname_len + 1);
                                 efree(lcname);                                  efree(lcname);
   
                                 if (!method_exists) {                                  if (!method_exists) {
Line 4070  static void zend_traits_compile_exclude_table(HashTabl Line 4002  static void zend_traits_compile_exclude_table(HashTabl
   
 static void zend_do_traits_method_binding(zend_class_entry *ce TSRMLS_DC) /* {{{ */  static void zend_do_traits_method_binding(zend_class_entry *ce TSRMLS_DC) /* {{{ */
 {  {
        HashTable** function_tables;        zend_uint i;
        HashTable* resulting_table;        HashTable *overriden = NULL;
        HashTable exclude_table; 
        size_t i; 
   
         /* prepare copies of trait function tables for combination */  
         function_tables = malloc(sizeof(HashTable*) * ce->num_traits);  
         resulting_table = (HashTable *) malloc(sizeof(HashTable));  
           
         /* TODO: revisit this start size, may be its not optimal */  
         zend_hash_init_ex(resulting_table, 10, NULL, NULL, 1, 0);  
     
         for (i = 0; i < ce->num_traits; i++) {          for (i = 0; i < ce->num_traits; i++) {
                 function_tables[i] = (HashTable *) malloc(sizeof(HashTable));  
                 zend_hash_init_ex(function_tables[i], ce->traits[i]->function_table.nNumOfElements, NULL, NULL, 1, 0);  
   
                 if (ce->trait_precedences) {                  if (ce->trait_precedences) {
                           HashTable exclude_table;
   
                         /* TODO: revisit this start size, may be its not optimal */                          /* TODO: revisit this start size, may be its not optimal */
                         zend_hash_init_ex(&exclude_table, 2, NULL, NULL, 0, 0);                          zend_hash_init_ex(&exclude_table, 2, NULL, NULL, 0, 0);
   
                         zend_traits_compile_exclude_table(&exclude_table, ce->trait_precedences, ce->traits[i]);                          zend_traits_compile_exclude_table(&exclude_table, ce->trait_precedences, ce->traits[i]);
   
                         /* copies functions, applies defined aliasing, and excludes unused trait methods */                          /* copies functions, applies defined aliasing, and excludes unused trait methods */
                        zend_traits_copy_trait_function_table(function_tables[i], &ce->traits[i]->function_table, ce->trait_aliases, &exclude_table TSRMLS_CC);                        zend_hash_apply_with_arguments(&ce->traits[i]->function_table TSRMLS_CC, (apply_func_args_t)zend_traits_copy_functions, 3, ce, &overriden, &exclude_table);
 
                         zend_hash_destroy(&exclude_table);                          zend_hash_destroy(&exclude_table);
                 } else {                  } else {
                        zend_traits_copy_trait_function_table(function_tables[i], &ce->traits[i]->function_table, ce->trait_aliases, NULL TSRMLS_CC);                        zend_hash_apply_with_arguments(&ce->traits[i]->function_table TSRMLS_CC, (apply_func_args_t)zend_traits_copy_functions, 3, ce, &overriden, NULL);
                 }                  }
         }          }
       
        /* now merge trait methods */    zend_hash_apply_with_argument(&ce->function_table, (apply_func_arg_t)zend_fixup_trait_method, ce TSRMLS_CC);
        for (i = 0; i < ce->num_traits; i++) { 
                zend_hash_apply_with_arguments(function_tables[i] TSRMLS_CC, (apply_func_args_t)zend_traits_merge_functions, 5, i, ce->num_traits, resulting_table, function_tables, ce); 
        } 
   
        /* Now the resulting_table contains all trait methods we would have to 
         * add to the class in the following step the methods are inserted into the method table 
         * if there is already a method with the same name it is replaced iff ce != fn.scope 
         * --> all inherited methods are overridden, methods defined in the class are left untouched 
         */ 
        zend_hash_apply_with_arguments(resulting_table TSRMLS_CC, (apply_func_args_t)zend_traits_merge_functions_to_class, 1, ce); 
   
        /* free temporary function tables */ 
        for (i = 0; i < ce->num_traits; i++) { 
                /* zend_hash_destroy(function_tables[i]); */ 
                zend_hash_graceful_destroy(function_tables[i]); 
                free(function_tables[i]); 
        } 
        free(function_tables); 
   
        /* free temporary resulting table */        if (overriden) {
        /* zend_hash_destroy(resulting_table); */                zend_hash_destroy(overriden);
        zend_hash_graceful_destroy(resulting_table);                FREE_HASHTABLE(overriden);
        free(resulting_table);        }
 }  }
 /* }}} */  /* }}} */
   
 static zend_class_entry* find_first_definition(zend_class_entry *ce, size_t current_trait, const char* prop_name, int prop_name_length, ulong prop_hash, zend_class_entry *coliding_ce) /* {{{ */  static zend_class_entry* find_first_definition(zend_class_entry *ce, size_t current_trait, const char* prop_name, int prop_name_length, ulong prop_hash, zend_class_entry *coliding_ce) /* {{{ */
 {  {
         size_t i;          size_t i;
        zend_property_info *coliding_prop;
        for (i = 0; (i < current_trait) && (i < ce->num_traits); i++) {        if (coliding_ce == ce) {
                if (zend_hash_quick_find(&ce->traits[i]->properties_info, prop_name, prop_name_length+1, prop_hash, (void **) &coliding_prop) == SUCCESS) {                for (i = 0; i < current_trait; i++) {
                        return ce->traits[i];                        if (zend_hash_quick_exists(&ce->traits[i]->properties_info, prop_name, prop_name_length+1, prop_hash)) {
                                 return ce->traits[i];
                         }
                 }                  }
         }          }
   
Line 4141  static zend_class_entry* find_first_definition(zend_cl Line 4048  static zend_class_entry* find_first_definition(zend_cl
 }  }
 /* }}} */  /* }}} */
   
 static void zend_traits_register_private_property(zend_class_entry *ce, const char *name, int name_len, zend_property_info *old_info, zval *property TSRMLS_DC) /* {{{ */  
 {  
         char *priv_name;  
         int priv_name_length;  
         const char *interned_name;  
         zend_property_info property_info;  
         ulong h = zend_get_hash_value(name, name_len+1);  
         property_info = *old_info;  
   
         if (old_info->flags & ZEND_ACC_STATIC) {  
                 property_info.offset = ce->default_static_members_count++;  
                 ce->default_static_members_table = perealloc(ce->default_static_members_table, sizeof(zval*) * ce->default_static_members_count, ce->type == ZEND_INTERNAL_CLASS);  
                 ce->default_static_members_table[property_info.offset] = property;  
                 if (ce->type == ZEND_USER_CLASS) {  
                         ce->static_members_table = ce->default_static_members_table;  
                 }  
         } else {  
                 property_info.offset = ce->default_properties_count++;  
                 ce->default_properties_table = perealloc(ce->default_properties_table, sizeof(zval*) * ce->default_properties_count, ce->type == ZEND_INTERNAL_CLASS);  
                 ce->default_properties_table[property_info.offset] = property;  
         }  
   
         zend_mangle_property_name(&priv_name, &priv_name_length, ce->name, ce->name_length, name, name_len, ce->type & ZEND_INTERNAL_CLASS);  
         property_info.name = priv_name;  
         property_info.name_length = priv_name_length;  
   
         interned_name = zend_new_interned_string(property_info.name, property_info.name_length+1, 0 TSRMLS_CC);  
         if (interned_name != property_info.name) {  
                 if (ce->type == ZEND_USER_CLASS) {  
                         efree((char*)property_info.name);  
                 } else {  
                         free((char*)property_info.name);  
                 }  
                 property_info.name = interned_name;  
         }  
   
         property_info.h = zend_get_hash_value(property_info.name, property_info.name_length+1);  
   
         property_info.ce = ce;  
   
         if (property_info.doc_comment) {  
                 property_info.doc_comment = estrndup(property_info.doc_comment, property_info.doc_comment_len);  
         }  
   
         zend_hash_quick_update(&ce->properties_info, name, name_len+1, h, &property_info, sizeof(zend_property_info), NULL);  
 }  
 /* }}} */  
   
 static void zend_do_traits_property_binding(zend_class_entry *ce TSRMLS_DC) /* {{{ */  static void zend_do_traits_property_binding(zend_class_entry *ce TSRMLS_DC) /* {{{ */
 {  {
         size_t i;          size_t i;
Line 4202  static void zend_do_traits_property_binding(zend_class Line 4061  static void zend_do_traits_property_binding(zend_class
         zend_bool not_compatible;          zend_bool not_compatible;
         zval* prop_value;          zval* prop_value;
         char* doc_comment;            char* doc_comment;  
          zend_uint flags;
 
         /* In the following steps the properties are inserted into the property table          /* In the following steps the properties are inserted into the property table
          * for that, a very strict approach is applied:           * for that, a very strict approach is applied:
          * - check for compatibility, if not compatible with any property in class -> fatal           * - check for compatibility, if not compatible with any property in class -> fatal
Line 4215  static void zend_do_traits_property_binding(zend_class Line 4075  static void zend_do_traits_property_binding(zend_class
                         /* first get the unmangeld name if necessary,                          /* first get the unmangeld name if necessary,
                          * then check whether the property is already there                           * then check whether the property is already there
                          */                           */
                        if ((property_info->flags & ZEND_ACC_PPP_MASK) == ZEND_ACC_PUBLIC) {                        flags = property_info->flags;
                         if ((flags & ZEND_ACC_PPP_MASK) == ZEND_ACC_PUBLIC) {
                                 prop_hash = property_info->h;                                  prop_hash = property_info->h;
                                 prop_name = property_info->name;                                  prop_name = property_info->name;
                                 prop_name_length = property_info->name_length;                                  prop_name_length = property_info->name_length;
Line 4229  static void zend_do_traits_property_binding(zend_class Line 4090  static void zend_do_traits_property_binding(zend_class
   
                         /* next: check for conflicts with current class */                          /* next: check for conflicts with current class */
                         if (zend_hash_quick_find(&ce->properties_info, prop_name, prop_name_length+1, prop_hash, (void **) &coliding_prop) == SUCCESS) {                          if (zend_hash_quick_find(&ce->properties_info, prop_name, prop_name_length+1, prop_hash, (void **) &coliding_prop) == SUCCESS) {
                                if (coliding_prop->flags & ZEND_ACC_SHADOW) {                                if (coliding_prop->flags & ZEND_ACC_SHADOW) {                                   
                                        /* this one is inherited, lets look it up in its own class */                                        zend_hash_quick_del(&ce->properties_info, prop_name, prop_name_length+1, prop_hash);
                                        zend_hash_quick_find(&coliding_prop->ce->properties_info, prop_name, prop_name_length+1, prop_hash, (void **) &coliding_prop);                                        flags |= ZEND_ACC_CHANGED;
                                        if (coliding_prop->flags & ZEND_ACC_PRIVATE) {                                } else {                                
                                                /* private property, make the property_info.offset indenpended */                                        if ((coliding_prop->flags & (ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC))
                                                if (property_info->flags & ZEND_ACC_STATIC) {                                                == (flags & (ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC))) {
                                                        prop_value = ce->traits[i]->default_static_members_table[property_info->offset];                                                /* 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 {                                                  } else {
                                                        prop_value = ce->traits[i]->default_properties_table[property_info->offset];                                                        not_compatible = (FAILURE == compare_function(&compare_result,
                                                                                           ce->default_properties_table[coliding_prop->offset],
                                                                                           ce->traits[i]->default_properties_table[property_info->offset] TSRMLS_CC))
                                                                   || (Z_LVAL(compare_result) != 0);
                                                 }                                                  }
                                                 Z_ADDREF_P(prop_value);  
   
                                                 zend_traits_register_private_property(ce, prop_name, prop_name_length, property_info, prop_value TSRMLS_CC);  
                                                 continue;  
                                         }  
                                 }  
                                   
                                 if ((coliding_prop->flags & (ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC))  
                                         == (property_info->flags & (ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC))) {  
                                         /* flags are identical, now the value needs to be checked */  
                                         if (property_info->flags & ZEND_ACC_STATIC) {  
                                                 not_compatible = (FAILURE == compare_function(&compare_result,  
                                                                                   ce->default_static_members_table[coliding_prop->offset],  
                                                                                   ce->traits[i]->default_static_members_table[property_info->offset] TSRMLS_CC))  
                                                           || (Z_LVAL(compare_result) != 0);  
                                         } else {                                          } else {
                                                not_compatible = (FAILURE == compare_function(&compare_result,                                                /* the flags are not identical, thus, we assume properties are not compatible */
                                                                                  ce->default_properties_table[coliding_prop->offset],                                                not_compatible = 1;
                                                                                  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) {                                        if (not_compatible) {
                                        zend_error(E_COMPILE_ERROR,                                                 zend_error(E_COMPILE_ERROR, 
                                                            "%s and %s define the same property ($%s) in the composition of %s. However, the definition differs and is considered incompatible. Class was composed",                                                             "%s and %s define the same property ($%s) in the composition of %s. However, the definition differs and is considered incompatible. Class was composed",
                                                                 find_first_definition(ce, i, prop_name, prop_name_length, prop_hash, coliding_prop->ce)->name,                                                                  find_first_definition(ce, i, prop_name, prop_name_length, prop_hash, coliding_prop->ce)->name,
                                                                 property_info->ce->name,                                                                  property_info->ce->name,
                                                                 prop_name,                                                                  prop_name,
                                                                 ce->name);                                                                  ce->name);
                                } else {                                        } else {
                                        zend_error(E_STRICT,                                                 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",                                                             "%s and %s define the same property ($%s) in the composition of %s. This might be incompatible, to improve maintainability consider using accessor methods in traits instead. Class was composed",
                                                                 find_first_definition(ce, i, prop_name, prop_name_length, prop_hash, coliding_prop->ce)->name,                                                                  find_first_definition(ce, i, prop_name, prop_name_length, prop_hash, coliding_prop->ce)->name,
                                                                 property_info->ce->name,                                                                  property_info->ce->name,
                                                                 prop_name,                                                                  prop_name,
                                                                 ce->name);                                                                  ce->name);
                                                   continue;
                                           }
                                 }                                  }
                         }                          }
   
                         /* property not found, so lets add it */                          /* property not found, so lets add it */
                        if (property_info->flags & ZEND_ACC_STATIC) {                        if (flags & ZEND_ACC_STATIC) {
                                 prop_value = ce->traits[i]->default_static_members_table[property_info->offset];                                  prop_value = ce->traits[i]->default_static_members_table[property_info->offset];
                         } else {                          } else {
                                 prop_value = ce->traits[i]->default_properties_table[property_info->offset];                                  prop_value = ce->traits[i]->default_properties_table[property_info->offset];
Line 4292  static void zend_do_traits_property_binding(zend_class Line 4142  static void zend_do_traits_property_binding(zend_class
   
                         doc_comment = property_info->doc_comment ? estrndup(property_info->doc_comment, property_info->doc_comment_len) : NULL;                          doc_comment = property_info->doc_comment ? estrndup(property_info->doc_comment, property_info->doc_comment_len) : NULL;
                         zend_declare_property_ex(ce, prop_name, prop_name_length,                           zend_declare_property_ex(ce, prop_name, prop_name_length, 
                                                                         prop_value, property_info->flags,                                                                          prop_value, flags, 
                                                                      doc_comment, property_info->doc_comment_len TSRMLS_CC);                                                                       doc_comment, property_info->doc_comment_len TSRMLS_CC);
                 }                  }
         }          }
Line 4416  ZEND_API int do_bind_function(const zend_op_array *op_ Line 4266  ZEND_API int do_bind_function(const zend_op_array *op_
 }  }
 /* }}} */  /* }}} */
   
 void zend_add_trait_precedence(znode *precedence_znode TSRMLS_DC) /* {{{ */  
 {  
         zend_class_entry *ce = CG(active_class_entry);  
         zend_add_to_list(&ce->trait_precedences, precedence_znode->u.op.ptr TSRMLS_CC);  
 }  
 /* }}} */  
   
 void zend_add_trait_alias(znode *alias_znode TSRMLS_DC) /* {{{ */  
 {  
         zend_class_entry *ce = CG(active_class_entry);  
         zend_add_to_list(&ce->trait_aliases, alias_znode->u.op.ptr TSRMLS_CC);  
 }  
 /* }}} */  
   
 void zend_prepare_reference(znode *result, znode *class_name, znode *method_name TSRMLS_DC) /* {{{ */  void zend_prepare_reference(znode *result, znode *class_name, znode *method_name TSRMLS_DC) /* {{{ */
 {  {
         zend_trait_method_reference *method_ref = emalloc(sizeof(zend_trait_method_reference));          zend_trait_method_reference *method_ref = emalloc(sizeof(zend_trait_method_reference));
Line 4454  void zend_prepare_reference(znode *result, znode *clas Line 4290  void zend_prepare_reference(znode *result, znode *clas
 }  }
 /* }}} */  /* }}} */
   
void zend_prepare_trait_alias(znode *result, znode *method_reference, znode *modifiers, znode *alias TSRMLS_DC) /* {{{ */void zend_add_trait_alias(znode *method_reference, znode *modifiers, znode *alias TSRMLS_DC) /* {{{ */
 {  {
        zend_trait_alias *trait_alias = emalloc(sizeof(zend_trait_alias));        zend_class_entry *ce = CG(active_class_entry);
         zend_trait_alias *trait_alias;
   
         trait_alias->trait_method = (zend_trait_method_reference*)method_reference->u.op.ptr;  
         trait_alias->modifiers = Z_LVAL(modifiers->u.constant);  
           
         if (Z_LVAL(modifiers->u.constant) == ZEND_ACC_STATIC) {          if (Z_LVAL(modifiers->u.constant) == ZEND_ACC_STATIC) {
                 zend_error(E_COMPILE_ERROR, "Cannot use 'static' as method modifier");                  zend_error(E_COMPILE_ERROR, "Cannot use 'static' as method modifier");
                 return;                  return;
           } else if (Z_LVAL(modifiers->u.constant) == ZEND_ACC_ABSTRACT) {
                   zend_error(E_COMPILE_ERROR, "Cannot use 'abstract' as method modifier");
                   return;
           } else if (Z_LVAL(modifiers->u.constant) == ZEND_ACC_FINAL) {
                   zend_error(E_COMPILE_ERROR, "Cannot use 'final' as method modifier");
                   return;
         }          }
   
           trait_alias = emalloc(sizeof(zend_trait_alias));
           trait_alias->trait_method = (zend_trait_method_reference*)method_reference->u.op.ptr;
           trait_alias->modifiers = Z_LVAL(modifiers->u.constant);
         if (alias) {          if (alias) {
                 trait_alias->alias = Z_STRVAL(alias->u.constant);                  trait_alias->alias = Z_STRVAL(alias->u.constant);
                 trait_alias->alias_len = Z_STRLEN(alias->u.constant);                  trait_alias->alias_len = Z_STRLEN(alias->u.constant);
Line 4474  void zend_prepare_trait_alias(znode *result, znode *me Line 4317  void zend_prepare_trait_alias(znode *result, znode *me
         }          }
         trait_alias->function = NULL;          trait_alias->function = NULL;
   
        result->u.op.ptr = trait_alias;        zend_add_to_list(&ce->trait_aliases, trait_alias TSRMLS_CC);
 }  }
 /* }}} */  /* }}} */
   
void zend_prepare_trait_precedence(znode *result, znode *method_reference, znode *trait_list TSRMLS_DC) /* {{{ */void zend_add_trait_precedence(znode *method_reference, znode *trait_list TSRMLS_DC) /* {{{ */
 {  {
           zend_class_entry *ce = CG(active_class_entry);
         zend_trait_precedence *trait_precedence = emalloc(sizeof(zend_trait_precedence));          zend_trait_precedence *trait_precedence = emalloc(sizeof(zend_trait_precedence));
   
         trait_precedence->trait_method = (zend_trait_method_reference*)method_reference->u.op.ptr;          trait_precedence->trait_method = (zend_trait_method_reference*)method_reference->u.op.ptr;
Line 4487  void zend_prepare_trait_precedence(znode *result, znod Line 4331  void zend_prepare_trait_precedence(znode *result, znod
   
         trait_precedence->function = NULL;          trait_precedence->function = NULL;
   
        result->u.op.ptr = trait_precedence;        zend_add_to_list(&ce->trait_precedences, trait_precedence TSRMLS_CC);
 }  }
 /* }}} */  /* }}} */
   
Line 4522  ZEND_API zend_class_entry *do_bind_class(const zend_op Line 4366  ZEND_API zend_class_entry *do_bind_class(const zend_op
                 }                  }
                 return NULL;                  return NULL;
         } else {          } else {
                if (!(ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_IMPLEMENT_INTERFACES))) {                if (!(ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_IMPLEMENT_INTERFACES|ZEND_ACC_IMPLEMENT_TRAITS))) {
                         zend_verify_abstract_class(ce TSRMLS_CC);                          zend_verify_abstract_class(ce TSRMLS_CC);
                 }                  }
                 return ce;                  return ce;
Line 4954  void zend_do_begin_class_declaration(const znode *clas Line 4798  void zend_do_begin_class_declaration(const znode *clas
                 /* Prefix class name with name of current namespace */                  /* Prefix class name with name of current namespace */
                 znode tmp;                  znode tmp;
   
                   tmp.op_type = IS_CONST;
                 tmp.u.constant = *CG(current_namespace);                  tmp.u.constant = *CG(current_namespace);
                 zval_copy_ctor(&tmp.u.constant);                  zval_copy_ctor(&tmp.u.constant);
                 zend_do_build_namespace_name(&tmp, &tmp, class_name TSRMLS_CC);                  zend_do_build_namespace_name(&tmp, &tmp, class_name TSRMLS_CC);
                class_name = &tmp;                *class_name = tmp;
                 efree(lcname);                  efree(lcname);
                 lcname = zend_str_tolower_dup(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant));                  lcname = zend_str_tolower_dup(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant));
         }          }
Line 5008  void zend_do_begin_class_declaration(const znode *clas Line 4853  void zend_do_begin_class_declaration(const znode *clas
         opline->op2_type = IS_CONST;          opline->op2_type = IS_CONST;
   
         if (doing_inheritance) {          if (doing_inheritance) {
       /* Make sure a trait does not try to extend a class */                /* Make sure a trait does not try to extend a class */
       if ((new_class_entry->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {                if ((new_class_entry->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {
           zend_error(E_COMPILE_ERROR, "A trait (%s) cannot extend a class. Traits can only be composed from other traits with the 'use' keyword. Error", new_class_entry->name);                        zend_error(E_COMPILE_ERROR, "A trait (%s) cannot extend a class. Traits can only be composed from other traits with the 'use' keyword. Error", new_class_entry->name);
       }                }
    
                 opline->extended_value = parent_class_name->u.op.var;                  opline->extended_value = parent_class_name->u.op.var;
                 opline->opcode = ZEND_DECLARE_INHERITED_CLASS;                  opline->opcode = ZEND_DECLARE_INHERITED_CLASS;
         } else {          } else {
Line 5090  void zend_do_end_class_declaration(const znode *class_ Line 4935  void zend_do_end_class_declaration(const znode *class_
         }          }
   
         if (!(ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS))          if (!(ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS))
                && ((parent_token->op_type != IS_UNUSED) || (ce->num_interfaces > 0))) {                && (parent_token || (ce->num_interfaces > 0))) {
                 zend_verify_abstract_class(ce TSRMLS_CC);                  zend_verify_abstract_class(ce TSRMLS_CC);
                if (ce->num_interfaces) {                if (ce->num_interfaces && !(ce->ce_flags & ZEND_ACC_IMPLEMENT_TRAITS)) {
                         do_verify_abstract_class(TSRMLS_C);                          do_verify_abstract_class(TSRMLS_C);
                 }                  }
         }          }
Line 5142  void zend_do_implements_interface(znode *interface_nam Line 4987  void zend_do_implements_interface(znode *interface_nam
 }  }
 /* }}} */  /* }}} */
   
void zend_do_implements_trait(znode *trait_name TSRMLS_DC) /* {{{ */void zend_do_use_trait(znode *trait_name TSRMLS_DC) /* {{{ */
 {  {
         zend_op *opline;          zend_op *opline;
   
         if ((CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE)) {          if ((CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE)) {
                 zend_error(E_COMPILE_ERROR,                  zend_error(E_COMPILE_ERROR,
                                 "Cannot use traits inside of interfaces. %s is used in %s",                                  "Cannot use traits inside of interfaces. %s is used in %s",
Line 5633  void zend_do_shell_exec(znode *result, const znode *cm Line 5479  void zend_do_shell_exec(znode *result, const znode *cm
                         break;                          break;
         }          }
         SET_NODE(opline->op1, cmd);          SET_NODE(opline->op1, cmd);
        opline->op2.opline_num = 0;        opline->op2.opline_num = 1;
         opline->extended_value = ZEND_DO_FCALL;          opline->extended_value = ZEND_DO_FCALL;
         SET_UNUSED(opline->op2);          SET_UNUSED(opline->op2);
   
Line 5874  void zend_add_to_list(void *result, void *item TSRMLS_ Line 5720  void zend_add_to_list(void *result, void *item TSRMLS_
         void** list = *(void**)result;          void** list = *(void**)result;
         size_t n = 0;          size_t n = 0;
   
        while (list && list[n]) { n++; }        if (list) {
                 while (list[n]) {
                         n++;
                 }
         }
   
         list = erealloc(list, sizeof(void*) * (n+2));          list = erealloc(list, sizeof(void*) * (n+2));
   
Line 6957  void zend_do_use(znode *ns_name, znode *new_name, int  Line 6807  void zend_do_use(znode *ns_name, znode *new_name, int 
         lcname = zend_str_tolower_dup(Z_STRVAL_P(name), Z_STRLEN_P(name));          lcname = zend_str_tolower_dup(Z_STRVAL_P(name), Z_STRLEN_P(name));
   
         if (((Z_STRLEN_P(name) == sizeof("self")-1) &&          if (((Z_STRLEN_P(name) == sizeof("self")-1) &&
          !memcmp(lcname, "self", sizeof("self")-1)) ||                                !memcmp(lcname, "self", sizeof("self")-1)) ||
            ((Z_STRLEN_P(name) == sizeof("parent")-1) &&                        ((Z_STRLEN_P(name) == sizeof("parent")-1) &&
          !memcmp(lcname, "parent", sizeof("parent")-1))) {           !memcmp(lcname, "parent", sizeof("parent")-1))) {
                 zend_error(E_COMPILE_ERROR, "Cannot use %s as %s because '%s' is a special class name", Z_STRVAL_P(ns), Z_STRVAL_P(name), Z_STRVAL_P(name));                  zend_error(E_COMPILE_ERROR, "Cannot use %s as %s because '%s' is a special class name", Z_STRVAL_P(ns), Z_STRVAL_P(name), Z_STRVAL_P(name));
         }          }
   
Line 7093  ZEND_API size_t zend_dirname(char *path, size_t len) Line 6943  ZEND_API size_t zend_dirname(char *path, size_t len)
         }          }
 #elif defined(NETWARE)  #elif defined(NETWARE)
         /*          /*
         * Find the first occurence of : from the left          * Find the first occurrence of : from the left
          * move the path pointer to the position just after :           * move the path pointer to the position just after :
          * increment the len_adjust to the length of path till colon character(inclusive)           * increment the len_adjust to the length of path till colon character(inclusive)
          * If there is no character beyond : simple return len           * If there is no character beyond : simple return len

Removed from v.1.1.1.2  
changed lines
  Added in v.1.1.1.3


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>