summaryrefslogtreecommitdiff
path: root/Zend/zend_inheritance.c
diff options
context:
space:
mode:
Diffstat (limited to 'Zend/zend_inheritance.c')
-rw-r--r--Zend/zend_inheritance.c154
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;