diff options
Diffstat (limited to 'Zend/zend_inheritance.c')
-rw-r--r-- | Zend/zend_inheritance.c | 240 |
1 files changed, 139 insertions, 101 deletions
diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index c69714ad19..ab188f2cfb 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -21,6 +21,7 @@ #include "zend_API.h" #include "zend_compile.h" #include "zend_execute.h" +#include "zend_inheritance.h" #include "zend_smart_str.h" static void ptr_dtor(zval *zv) /* {{{ */ @@ -211,6 +212,90 @@ static zend_function *do_inherit_method(zend_function *old_function, zend_class_ } /* }}} */ +static int zend_do_perform_type_hint_check(zend_function *fe, zend_arg_info *fe_arg_info, zend_function *proto, zend_arg_info *proto_arg_info) /* {{{ */ +{ + if (ZEND_LOG_XOR(fe_arg_info->class_name, proto_arg_info->class_name)) { + /* Only one has a type hint and the other one doesn't */ + return 0; + } + + if (fe_arg_info->class_name) { + zend_string *fe_class_name, *proto_class_name; + const char *class_name; + + if (fe->type == ZEND_INTERNAL_FUNCTION) { + fe_class_name = NULL; + class_name = ((zend_internal_arg_info*)fe_arg_info)->class_name; + } else { + fe_class_name = fe_arg_info->class_name; + class_name = fe_arg_info->class_name->val; + } + if (!strcasecmp(class_name, "parent") && proto->common.scope) { + fe_class_name = zend_string_copy(proto->common.scope->name); + } else if (!strcasecmp(class_name, "self") && fe->common.scope) { + fe_class_name = zend_string_copy(fe->common.scope->name); + } else if (fe_class_name) { + zend_string_addref(fe_class_name); + } else { + fe_class_name = zend_string_init(class_name, strlen(class_name), 0); + } + + if (proto->type == ZEND_INTERNAL_FUNCTION) { + proto_class_name = NULL; + class_name = ((zend_internal_arg_info*)proto_arg_info)->class_name; + } else { + proto_class_name = proto_arg_info->class_name; + class_name = proto_arg_info->class_name->val; + } + if (!strcasecmp(class_name, "parent") && proto->common.scope && proto->common.scope->parent) { + proto_class_name = zend_string_copy(proto->common.scope->parent->name); + } else if (!strcasecmp(class_name, "self") && proto->common.scope) { + proto_class_name = zend_string_copy(proto->common.scope->name); + } else if (proto_class_name) { + zend_string_addref(proto_class_name); + } else { + proto_class_name = zend_string_init(class_name, strlen(class_name), 0); + } + + if (strcasecmp(fe_class_name->val, proto_class_name->val) != 0) { + const char *colon; + + if (fe->common.type != ZEND_USER_FUNCTION) { + zend_string_release(proto_class_name); + zend_string_release(fe_class_name); + return 0; + } else if (strchr(proto_class_name->val, '\\') != NULL || + (colon = zend_memrchr(fe_class_name->val, '\\', fe_class_name->len)) == NULL || + strcasecmp(colon+1, proto_class_name->val) != 0) { + zend_class_entry *fe_ce, *proto_ce; + + fe_ce = zend_lookup_class(fe_class_name); + proto_ce = zend_lookup_class(proto_class_name); + + /* Check for class alias */ + if (!fe_ce || !proto_ce || + fe_ce->type == ZEND_INTERNAL_CLASS || + proto_ce->type == ZEND_INTERNAL_CLASS || + fe_ce != proto_ce) { + zend_string_release(proto_class_name); + zend_string_release(fe_class_name); + return 0; + } + } + } + zend_string_release(proto_class_name); + zend_string_release(fe_class_name); + } + + if (fe_arg_info->type_hint != proto_arg_info->type_hint) { + /* Incompatible type hint */ + return 0; + } + + return 1; +} +/* }}} */ + static zend_bool zend_do_perform_implementation_check(const zend_function *fe, const zend_function *proto) /* {{{ */ { uint32_t i, num_args; @@ -279,90 +364,62 @@ static zend_bool zend_do_perform_implementation_check(const zend_function *fe, c proto_arg_info = &proto->common.arg_info[proto->common.num_args]; } - if (ZEND_LOG_XOR(fe_arg_info->class_name, proto_arg_info->class_name)) { - /* Only one has a type hint and the other one doesn't */ + if (!zend_do_perform_type_hint_check(fe, fe_arg_info, proto, proto_arg_info)) { return 0; } - if (fe_arg_info->class_name) { - zend_string *fe_class_name, *proto_class_name; - const char *class_name; - - if (fe->type == ZEND_INTERNAL_FUNCTION) { - fe_class_name = NULL; - class_name = ((zend_internal_arg_info*)fe_arg_info)->class_name; - } else { - fe_class_name = fe_arg_info->class_name; - class_name = fe_arg_info->class_name->val; - } - if (!strcasecmp(class_name, "parent") && proto->common.scope) { - fe_class_name = zend_string_copy(proto->common.scope->name); - } else if (!strcasecmp(class_name, "self") && fe->common.scope) { - fe_class_name = zend_string_copy(fe->common.scope->name); - } else if (fe_class_name) { - zend_string_addref(fe_class_name); - } else { - fe_class_name = zend_string_init(class_name, strlen(class_name), 0); - } + /* by-ref constraints on arguments are invariant */ + if (fe_arg_info->pass_by_reference != proto_arg_info->pass_by_reference) { + return 0; + } + } - if (proto->type == ZEND_INTERNAL_FUNCTION) { - proto_class_name = NULL; - class_name = ((zend_internal_arg_info*)proto_arg_info)->class_name; - } else { - proto_class_name = proto_arg_info->class_name; - class_name = proto_arg_info->class_name->val; - } - if (!strcasecmp(class_name, "parent") && proto->common.scope && proto->common.scope->parent) { - proto_class_name = zend_string_copy(proto->common.scope->parent->name); - } else if (!strcasecmp(class_name, "self") && proto->common.scope) { - proto_class_name = zend_string_copy(proto->common.scope->name); - } else if (proto_class_name) { - zend_string_addref(proto_class_name); - } else { - proto_class_name = zend_string_init(class_name, strlen(class_name), 0); - } + /* check return type compataibility */ + if ((proto->common.fn_flags | fe->common.fn_flags) & ZEND_ACC_HAS_RETURN_TYPE) { + if ((proto->common.fn_flags ^ fe->common.fn_flags) & ZEND_ACC_HAS_RETURN_TYPE) { + return 0; + } + if (!zend_do_perform_type_hint_check(fe, fe->common.arg_info - 1, proto, proto->common.arg_info - 1)) { + return 0; + } + } + return 1; +} +/* }}} */ - if (strcasecmp(fe_class_name->val, proto_class_name->val)!=0) { - const char *colon; +static void zend_append_type_hint(smart_str *str, zend_function *fptr, zend_arg_info *arg_info, int return_hint) /* {{{ */ +{ + if (arg_info->class_name) { + const char *class_name; + size_t class_name_len; - if (fe->common.type != ZEND_USER_FUNCTION) { - zend_string_release(proto_class_name); - zend_string_release(fe_class_name); - return 0; - } else if (strchr(proto_class_name->val, '\\') != NULL || - (colon = zend_memrchr(fe_class_name->val, '\\', fe_class_name->len)) == NULL || - strcasecmp(colon+1, proto_class_name->val) != 0) { - zend_class_entry *fe_ce, *proto_ce; - - fe_ce = zend_lookup_class(fe_class_name); - proto_ce = zend_lookup_class(proto_class_name); - - /* Check for class alias */ - if (!fe_ce || !proto_ce || - fe_ce->type == ZEND_INTERNAL_CLASS || - proto_ce->type == ZEND_INTERNAL_CLASS || - fe_ce != proto_ce) { - zend_string_release(proto_class_name); - zend_string_release(fe_class_name); - return 0; - } - } - } - zend_string_release(proto_class_name); - zend_string_release(fe_class_name); + if (fptr->type == ZEND_INTERNAL_FUNCTION) { + class_name = ((zend_internal_arg_info*)arg_info)->class_name; + class_name_len = strlen(class_name); + } else { + class_name = arg_info->class_name->val; + class_name_len = arg_info->class_name->len; } - if (fe_arg_info->type_hint != proto_arg_info->type_hint) { - /* Incompatible type hint */ - return 0; + + if (!strcasecmp(class_name, "self") && fptr->common.scope) { + class_name = fptr->common.scope->name->val; + class_name_len = fptr->common.scope->name->len; + } else if (!strcasecmp(class_name, "parent") && fptr->common.scope->parent) { + class_name = fptr->common.scope->parent->name->val; + class_name_len = fptr->common.scope->parent->name->len; } - /* by-ref constraints on arguments are invariant */ - if (fe_arg_info->pass_by_reference != proto_arg_info->pass_by_reference) { - return 0; + smart_str_appendl(str, class_name, class_name_len); + if (!return_hint) { + smart_str_appendc(str, ' '); + } + } else if (arg_info->type_hint) { + const char *type_name = zend_get_type_by_const(arg_info->type_hint); + smart_str_appends(str, type_name); + if (!return_hint) { + smart_str_appendc(str, ' '); } } - - return 1; } /* }}} */ @@ -392,33 +449,7 @@ static zend_string *zend_get_function_declaration(zend_function *fptr) /* {{{ */ num_args++; } for (i = 0; i < num_args;) { - if (arg_info->class_name) { - const char *class_name; - size_t class_name_len; - - if (fptr->type == ZEND_INTERNAL_FUNCTION) { - class_name = ((zend_internal_arg_info*)arg_info)->class_name; - class_name_len = strlen(class_name); - } else { - class_name = arg_info->class_name->val; - class_name_len = arg_info->class_name->len; - } - - if (!strcasecmp(class_name, "self") && fptr->common.scope) { - class_name = fptr->common.scope->name->val; - class_name_len = fptr->common.scope->name->len; - } else if (!strcasecmp(class_name, "parent") && fptr->common.scope->parent) { - class_name = fptr->common.scope->parent->name->val; - class_name_len = fptr->common.scope->parent->name->len; - } - - smart_str_appendl(&str, class_name, class_name_len); - smart_str_appendc(&str, ' '); - } else if (arg_info->type_hint) { - const char *type_name = zend_get_type_by_const(arg_info->type_hint); - smart_str_appends(&str, type_name); - smart_str_appendc(&str, ' '); - } + zend_append_type_hint(&str, fptr, arg_info, 0); if (arg_info->pass_by_reference) { smart_str_appendc(&str, '&'); @@ -501,6 +532,11 @@ static zend_string *zend_get_function_declaration(zend_function *fptr) /* {{{ */ } smart_str_appendc(&str, ')'); + + if (fptr->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) { + smart_str_appends(&str, ": "); + zend_append_type_hint(&str, fptr, fptr->common.arg_info - 1, 1); + } smart_str_0(&str); return str.s; @@ -565,7 +601,9 @@ static void do_inheritance_check_on_method(zend_function *child, zend_function * child->common.prototype = parent->common.prototype ? parent->common.prototype : parent; } - if (child->common.prototype && (child->common.prototype->common.fn_flags & ZEND_ACC_ABSTRACT)) { + if (child->common.prototype && ( + child->common.prototype->common.fn_flags & (ZEND_ACC_ABSTRACT | ZEND_ACC_HAS_RETURN_TYPE) + )) { if (!zend_do_perform_implementation_check(child, child->common.prototype)) { zend_error_noreturn(E_COMPILE_ERROR, "Declaration of %s::%s() must be compatible with %s", ZEND_FN_SCOPE_NAME(child), child->common.function_name->val, zend_get_function_declaration(child->common.prototype)->val); } |