diff options
Diffstat (limited to 'Zend/zend_inheritance.c')
| -rw-r--r-- | Zend/zend_inheritance.c | 154 |
1 files changed, 82 insertions, 72 deletions
diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index d9711977bf..c6a89754c9 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -90,22 +90,24 @@ static zend_function *zend_duplicate_function(zend_function *func, zend_class_en static void do_inherit_parent_constructor(zend_class_entry *ce) /* {{{ */ { - ZEND_ASSERT(ce->parent != NULL); + zend_class_entry *parent = ce->parent; + + ZEND_ASSERT(parent != NULL); /* You cannot change create_object */ - ce->create_object = ce->parent->create_object; + ce->create_object = parent->create_object; /* Inherit special functions if needed */ if (EXPECTED(!ce->get_iterator)) { - ce->get_iterator = ce->parent->get_iterator; + ce->get_iterator = parent->get_iterator; } - if (EXPECTED(!ce->iterator_funcs_ptr) && UNEXPECTED(ce->parent->iterator_funcs_ptr)) { + if (EXPECTED(!ce->iterator_funcs_ptr) && UNEXPECTED(parent->iterator_funcs_ptr)) { if (ce->type == ZEND_INTERNAL_CLASS) { ce->iterator_funcs_ptr = calloc(1, sizeof(zend_class_iterator_funcs)); - if (ce->parent->iterator_funcs_ptr->zf_new_iterator) { + if (parent->iterator_funcs_ptr->zf_new_iterator) { ce->iterator_funcs_ptr->zf_new_iterator = zend_hash_str_find_ptr(&ce->function_table, "getiterator", sizeof("getiterator") - 1); } - if (ce->parent->iterator_funcs_ptr->zf_current) { + if (parent->iterator_funcs_ptr->zf_current) { ce->iterator_funcs_ptr->zf_rewind = zend_hash_str_find_ptr(&ce->function_table, "rewind", sizeof("rewind") - 1); ce->iterator_funcs_ptr->zf_valid = zend_hash_str_find_ptr(&ce->function_table, "valid", sizeof("valid") - 1); ce->iterator_funcs_ptr->zf_key = zend_hash_str_find_ptr(&ce->function_table, "key", sizeof("key") - 1); @@ -118,52 +120,52 @@ static void do_inherit_parent_constructor(zend_class_entry *ce) /* {{{ */ } } if (EXPECTED(!ce->__get)) { - ce->__get = ce->parent->__get; + ce->__get = parent->__get; } if (EXPECTED(!ce->__set)) { - ce->__set = ce->parent->__set; + ce->__set = parent->__set; } if (EXPECTED(!ce->__unset)) { - ce->__unset = ce->parent->__unset; + ce->__unset = parent->__unset; } if (EXPECTED(!ce->__isset)) { - ce->__isset = ce->parent->__isset; + ce->__isset = parent->__isset; } if (EXPECTED(!ce->__call)) { - ce->__call = ce->parent->__call; + ce->__call = parent->__call; } if (EXPECTED(!ce->__callstatic)) { - ce->__callstatic = ce->parent->__callstatic; + ce->__callstatic = parent->__callstatic; } if (EXPECTED(!ce->__tostring)) { - ce->__tostring = ce->parent->__tostring; + ce->__tostring = parent->__tostring; } if (EXPECTED(!ce->clone)) { - ce->clone = ce->parent->clone; + ce->clone = parent->clone; } if (EXPECTED(!ce->serialize)) { - ce->serialize = ce->parent->serialize; + ce->serialize = parent->serialize; } if (EXPECTED(!ce->unserialize)) { - ce->unserialize = ce->parent->unserialize; + ce->unserialize = parent->unserialize; } if (!ce->destructor) { - ce->destructor = ce->parent->destructor; + ce->destructor = parent->destructor; } if (EXPECTED(!ce->__debugInfo)) { - ce->__debugInfo = ce->parent->__debugInfo; + ce->__debugInfo = parent->__debugInfo; } if (ce->constructor) { - if (ce->parent->constructor && UNEXPECTED(ce->parent->constructor->common.fn_flags & ZEND_ACC_FINAL)) { + if (parent->constructor && UNEXPECTED(parent->constructor->common.fn_flags & ZEND_ACC_FINAL)) { zend_error_noreturn(E_ERROR, "Cannot override final %s::%s() with %s::%s()", - ZSTR_VAL(ce->parent->name), ZSTR_VAL(ce->parent->constructor->common.function_name), + ZSTR_VAL(parent->name), ZSTR_VAL(parent->constructor->common.function_name), ZSTR_VAL(ce->name), ZSTR_VAL(ce->constructor->common.function_name)); } return; } - ce->constructor = ce->parent->constructor; + ce->constructor = parent->constructor; } /* }}} */ @@ -284,14 +286,14 @@ static zend_bool zend_do_perform_implementation_check(const zend_function *fe, c * 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)) { + if (!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) + if ((fe->common.scope->constructor == fe) && ((proto->common.scope->ce_flags & ZEND_ACC_INTERFACE) == 0 && (proto->common.fn_flags & ZEND_ACC_ABSTRACT) == 0)) { return 1; @@ -584,55 +586,64 @@ static void do_inheritance_check_on_method(zend_function *child, zend_function * zend_error_noreturn(E_COMPILE_ERROR, "Cannot make non abstract method %s::%s() abstract in class %s", ZEND_FN_SCOPE_NAME(parent), ZSTR_VAL(child->common.function_name), ZEND_FN_SCOPE_NAME(child)); } - /* Prevent derived classes from restricting access that was available in parent classes (except deriving from non-abstract ctors) */ - if (UNEXPECTED((!(child_flags & ZEND_ACC_CTOR) || (parent_flags & (ZEND_ACC_ABSTRACT | ZEND_ACC_IMPLEMENTED_ABSTRACT))) && - (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), ZSTR_VAL(child->common.function_name), zend_visibility_string(parent_flags), ZEND_FN_SCOPE_NAME(parent), (parent_flags&ZEND_ACC_PUBLIC) ? "" : " or weaker"); - } - if ((child_flags & ZEND_ACC_PRIVATE) < (parent_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_CHANGED))) { 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)) { - child->common.prototype = parent->common.prototype ? parent->common.prototype : parent; - } else if (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; - /* and if that is the case, we want to check inheritance against it */ - parent = child->common.prototype; - } - - if (UNEXPECTED(!zend_do_perform_implementation_check(child, parent))) { - int error_level; - const char *error_verb; - zend_string *method_prototype = zend_get_function_declaration(parent); - zend_string *child_prototype = zend_get_function_declaration(child); - - if (child->common.prototype && ( - child->common.prototype->common.fn_flags & ZEND_ACC_ABSTRACT - )) { - error_level = E_COMPILE_ERROR; - error_verb = "must"; - } else if ((parent->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) && - (!(child->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) || - !zend_do_perform_type_hint_check(child, child->common.arg_info - 1, parent, parent->common.arg_info - 1) || - (ZEND_TYPE_ALLOW_NULL(child->common.arg_info[-1].type) && !ZEND_TYPE_ALLOW_NULL(parent->common.arg_info[-1].type)))) { - error_level = E_COMPILE_ERROR; - error_verb = "must"; - } else { - error_level = E_WARNING; - error_verb = "should"; + do { + if (!(parent_flags & ZEND_ACC_PRIVATE)) { + if (parent_flags & ZEND_ACC_ABSTRACT) { + child->common.prototype = parent; + } else { + zend_function *proto = parent->common.prototype; + + if (parent->common.scope->constructor != parent) { + child->common.prototype = proto ? proto : parent; + } else if (proto) { + if (proto->common.scope->ce_flags & ZEND_ACC_INTERFACE) { + /* ctors only have a prototype if it comes from an interface */ + child->common.prototype = proto; + /* and if that is the case, we want to check inheritance against it */ + parent = proto; + } else if (!(proto->common.fn_flags & ZEND_ACC_ABSTRACT)) { + break; + } + } else { + break; + } + } + /* Prevent derived classes from restricting access that was available in parent classes (except deriving from non-abstract ctors) */ + 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), ZSTR_VAL(child->common.function_name), zend_visibility_string(parent_flags), ZEND_FN_SCOPE_NAME(parent), (parent_flags&ZEND_ACC_PUBLIC) ? "" : " or weaker"); + } + + if (UNEXPECTED(!zend_do_perform_implementation_check(child, parent))) { + int error_level; + const char *error_verb; + zend_string *method_prototype = zend_get_function_declaration(parent); + zend_string *child_prototype = zend_get_function_declaration(child); + + if (child->common.prototype && ( + child->common.prototype->common.fn_flags & ZEND_ACC_ABSTRACT + )) { + error_level = E_COMPILE_ERROR; + error_verb = "must"; + } else if ((parent->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) && + (!(child->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) || + !zend_do_perform_type_hint_check(child, child->common.arg_info - 1, parent, parent->common.arg_info - 1) || + (ZEND_TYPE_ALLOW_NULL(child->common.arg_info[-1].type) && !ZEND_TYPE_ALLOW_NULL(parent->common.arg_info[-1].type)))) { + error_level = E_COMPILE_ERROR; + error_verb = "must"; + } else { + error_level = E_WARNING; + error_verb = "should"; + } + zend_error(error_level, "Declaration of %s %s be compatible with %s", ZSTR_VAL(child_prototype), error_verb, ZSTR_VAL(method_prototype)); + zend_string_efree(child_prototype); + zend_string_efree(method_prototype); + } } - zend_error(error_level, "Declaration of %s %s be compatible with %s", ZSTR_VAL(child_prototype), error_verb, ZSTR_VAL(method_prototype)); - zend_string_efree(child_prototype); - zend_string_efree(method_prototype); - } + } while (0); } /* }}} */ @@ -1202,11 +1213,10 @@ static void zend_add_magic_methods(zend_class_entry* ce, zend_string* mname, zen zend_string *lowercase_name = zend_string_tolower(ce->name); lowercase_name = zend_new_interned_string(lowercase_name); if (!memcmp(ZSTR_VAL(mname), ZSTR_VAL(lowercase_name), ZSTR_LEN(mname))) { - if (ce->constructor && (!ce->parent || ce->constructor != ce->parent->constructor)) { + if (ce->constructor && (!ce->parent || ce->constructor != ce->parent->constructor)) { zend_error_noreturn(E_COMPILE_ERROR, "%s has colliding constructor definitions coming from traits", ZSTR_VAL(ce->name)); } ce->constructor = fe; - fe->common.fn_flags |= ZEND_ACC_CTOR; } zend_string_release_ex(lowercase_name, 0); } else if (ZSTR_VAL(mname)[0] != '_' || ZSTR_VAL(mname)[1] != '_') { @@ -1217,9 +1227,9 @@ static void zend_add_magic_methods(zend_class_entry* ce, zend_string* mname, zen if (ce->constructor && (!ce->parent || ce->constructor != ce->parent->constructor)) { zend_error_noreturn(E_COMPILE_ERROR, "%s has colliding constructor definitions coming from traits", ZSTR_VAL(ce->name)); } - ce->constructor = fe; fe->common.fn_flags |= ZEND_ACC_CTOR; + ce->constructor = fe; } else if (zend_string_equals_literal(mname, ZEND_DESTRUCTOR_FUNC_NAME)) { - ce->destructor = fe; fe->common.fn_flags |= ZEND_ACC_DTOR; + ce->destructor = fe; } else if (zend_string_equals_literal(mname, ZEND_GET_FUNC_NAME)) { ce->__get = fe; ce->ce_flags |= ZEND_ACC_USE_GUARDS; @@ -1903,7 +1913,7 @@ static void zend_verify_abstract_class_function(zend_function *fn, zend_abstract if (ai->cnt < MAX_ABSTRACT_INFO_CNT) { ai->afn[ai->cnt] = fn; } - if (fn->common.fn_flags & ZEND_ACC_CTOR) { + if (fn->common.scope->constructor == fn) { if (!ai->ctor) { ai->cnt++; ai->ctor = 1; |
