From: Dmitry Stogov Date: Thu, 12 Jul 2007 09:23:48 +0000 (+0000) Subject: Namespaces X-Git-Tag: BEFORE_IMPORT_OF_MYSQLND~199 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1f413bbc37635589ad750577c0cf370d84977ba1;p=php Namespaces --- diff --git a/NEWS b/NEWS index 82c9faa85c..6a6ee68333 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,7 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? 20??, PHP 6.0 - Unicode support. (Andrei, Dmitry, et al) +- Namespaces. (Dmitry, Stas) - Changed dl() to be disabled by default. Enabled only when explicitly registered by the SAPI layer. Enabled only with CLI, CGI and EMBED. (Dmitry) diff --git a/Zend/tests/ns_001.phpt b/Zend/tests/ns_001.phpt new file mode 100755 index 0000000000..6821756a43 --- /dev/null +++ b/Zend/tests/ns_001.phpt @@ -0,0 +1,34 @@ +--TEST-- +001: Class in namespace +--FILE-- +bar(); +Foo::baz(); +$y = new test::ns1::Foo; +$y->bar(); +test::ns1::Foo::baz(); +--EXPECT-- +test::ns1::Foo +test::ns1::Foo +test::ns1::Foo +test::ns1::Foo +test::ns1::Foo +test::ns1::Foo diff --git a/Zend/tests/ns_002.phpt b/Zend/tests/ns_002.phpt new file mode 100755 index 0000000000..4b17012a94 --- /dev/null +++ b/Zend/tests/ns_002.phpt @@ -0,0 +1,27 @@ +--TEST-- +002: Import in namespace +--FILE-- + Z_STRVAL_P(callable) && + *(colon.s-1) == ':') { + colon.s--; clen = colon.s - Z_STRVAL_P(callable); mlen = Z_STRLEN_P(callable) - clen - 2; mname.s = colon.s + 2; diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index f0b747e1fc..50717a076c 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -164,6 +164,8 @@ void zend_init_compiler_data_structures(TSRMLS_D) /* {{{ */ zend_hash_apply(CG(auto_globals), (apply_func_t) zend_auto_global_arm TSRMLS_CC); zend_stack_init(&CG(labels_stack)); CG(labels) = NULL; + CG(current_namespace) = NULL; + CG(current_import) = NULL; } /* }}} */ @@ -437,13 +439,15 @@ void fetch_simple_variable(znode *result, znode *varname, int bp TSRMLS_DC) /* { } /* }}} */ -void zend_do_fetch_static_member(znode *result, znode *class_znode TSRMLS_DC) /* {{{ */ +void zend_do_fetch_static_member(znode *result, znode *class_name TSRMLS_DC) /* {{{ */ { + znode class_node; zend_llist *fetch_list_ptr; zend_llist_element *le; zend_op *opline_ptr; zend_op opline; + zend_do_fetch_class(&class_node, class_name TSRMLS_CC); zend_stack_top(&CG(bp_stack), (void **) &fetch_list_ptr); if (result->op_type == IS_CV) { init_op(&opline TSRMLS_CC); @@ -457,7 +461,7 @@ void zend_do_fetch_static_member(znode *result, znode *class_znode TSRMLS_DC) /* CG(active_op_array)->vars[result->u.var].name, CG(active_op_array)->vars[result->u.var].name_len, 1); SET_UNUSED(opline.op2); - opline.op2 = *class_znode; + opline.op2 = class_node; opline.op2.u.EA.type = ZEND_FETCH_STATIC_MEMBER; *result = opline.result; @@ -477,13 +481,13 @@ void zend_do_fetch_static_member(znode *result, znode *class_znode TSRMLS_DC) /* CG(active_op_array)->vars[opline_ptr->op1.u.var].name, CG(active_op_array)->vars[opline_ptr->op1.u.var].name_len, 1); SET_UNUSED(opline.op2); - opline.op2 = *class_znode; + opline.op2 = class_node; opline.op2.u.EA.type = ZEND_FETCH_STATIC_MEMBER; opline_ptr->op1 = opline.result; zend_llist_prepend_element(fetch_list_ptr, &opline); } else { - opline_ptr->op2 = *class_znode; + opline_ptr->op2 = class_node; opline_ptr->op2.u.EA.type = ZEND_FETCH_STATIC_MEMBER; } } @@ -1238,13 +1242,24 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n } else { zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); + if (CG(current_namespace)) { + znode tmp; + + tmp.u.constant = *CG(current_namespace); + zval_copy_ctor(&tmp.u.constant); + zend_do_build_namespace_name(&tmp, &tmp, function_name TSRMLS_CC); + op_array.function_name = Z_UNIVAL(tmp.u.constant); + efree(lcname.v); + lcname = zend_u_str_case_fold(Z_TYPE(tmp.u.constant), Z_UNIVAL(tmp.u.constant), Z_UNILEN(tmp.u.constant), 0, &lcname_len); + } + opline->opcode = ZEND_DECLARE_FUNCTION; opline->op1.op_type = IS_CONST; build_runtime_defined_function_key(&opline->op1.u.constant, Z_TYPE(function_name->u.constant), lcname, lcname_len TSRMLS_CC); opline->op2.op_type = IS_CONST; Z_TYPE(opline->op2.u.constant) = Z_TYPE(function_name->u.constant); - Z_STRVAL(opline->op2.u.constant) = lcname.s; - Z_STRLEN(opline->op2.u.constant) = lcname_len; + Z_UNIVAL(opline->op2.u.constant) = lcname; + Z_UNILEN(opline->op2.u.constant) = lcname_len; opline->op2.u.constant.refcount = 1; opline->extended_value = ZEND_DECLARE_FUNCTION; zend_u_hash_update(CG(function_table), Z_TYPE(opline->op1.u.constant), Z_UNIVAL(opline->op1.u.constant), Z_UNILEN(opline->op1.u.constant), &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array)); @@ -1429,12 +1444,22 @@ void zend_do_receive_arg(zend_uchar op, znode *var, znode *offset, znode *initia } /* }}} */ -int zend_do_begin_function_call(znode *function_name TSRMLS_DC) /* {{{ */ +int zend_do_begin_function_call(znode *function_name, zend_bool check_namespace TSRMLS_DC) /* {{{ */ { zend_function *function; unsigned int lcname_len; zstr lcname; + if (check_namespace && CG(current_namespace)) { + znode tmp; + + tmp.op_type = IS_CONST; + tmp.u.constant = *CG(current_namespace); + zval_copy_ctor(&tmp.u.constant); + zend_do_build_namespace_name(&tmp, &tmp, function_name TSRMLS_CC); + *function_name = tmp; + } + lcname = zend_u_str_case_fold(Z_TYPE(function_name->u.constant), Z_UNIVAL(function_name->u.constant), Z_UNILEN(function_name->u.constant), 0, &lcname_len); if (zend_u_hash_find(CG(function_table), Z_TYPE(function_name->u.constant), lcname, lcname_len+1, (void **) &function)==FAILURE) { zend_do_begin_dynamic_function_call(function_name TSRMLS_CC); @@ -1442,12 +1467,8 @@ int zend_do_begin_function_call(znode *function_name TSRMLS_DC) /* {{{ */ return 1; /* Dynamic */ } efree(Z_UNIVAL(function_name->u.constant).v); - if (Z_TYPE(function_name->u.constant) == IS_UNICODE) { - Z_USTRVAL(function_name->u.constant) = lcname.u; - Z_USTRLEN(function_name->u.constant) = lcname_len; - } else { - Z_STRVAL(function_name->u.constant) = lcname.s; - } + Z_UNIVAL(function_name->u.constant) = lcname; + Z_UNILEN(function_name->u.constant) = lcname_len; switch (function->type) { case ZEND_USER_FUNCTION: { @@ -1535,12 +1556,106 @@ void zend_do_begin_dynamic_function_call(znode *function_name TSRMLS_DC) /* {{{ opline->extended_value = 0; SET_UNUSED(opline->op1); + if (function_name->op_type == IS_CONST) { + if (Z_TYPE(function_name->u.constant) == IS_UNICODE) { + UChar *p = u_memrchr(Z_USTRVAL(function_name->u.constant), ':', Z_USTRLEN(function_name->u.constant)); + if (p) { + opline->op1.op_type = IS_CONST; + ZVAL_LONG(&opline->op1.u.constant, p + 1 - Z_USTRVAL(function_name->u.constant)); + } + } else { + char *p = zend_memrchr(Z_STRVAL(function_name->u.constant), ':', Z_STRLEN(function_name->u.constant)); + if (p) { + opline->op1.op_type = IS_CONST; + ZVAL_LONG(&opline->op1.u.constant, p + 1 - Z_STRVAL(function_name->u.constant)); + } + } + } zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(zend_function *)); zend_do_extended_fcall_begin(TSRMLS_C); } /* }}} */ +void zend_resolve_class_name(znode *class_name, ulong *fetch_type TSRMLS_DC) /* {{{ */ +{ + zstr compound; + unsigned int lcname_len; + zstr lcname; + zval **ns; + znode tmp; + int len; + + if (Z_TYPE(class_name->u.constant) == IS_UNICODE) { + compound.u = u_memchr(Z_USTRVAL(class_name->u.constant), ':', Z_USTRLEN(class_name->u.constant)); + } else { + compound.s = memchr(Z_STRVAL(class_name->u.constant), ':', Z_STRLEN(class_name->u.constant)); + } + if (compound.v) { + if (Z_TYPE(class_name->u.constant) == IS_UNICODE && + Z_USTRVAL(class_name->u.constant)[0] == ':') { + Z_USTRLEN(class_name->u.constant) -= 2; + memmove(Z_USTRVAL(class_name->u.constant), Z_USTRVAL(class_name->u.constant)+2, UBYTES(Z_USTRLEN(class_name->u.constant)+1)); + Z_USTRVAL(class_name->u.constant) = eurealloc( + Z_USTRVAL(class_name->u.constant), + Z_USTRLEN(class_name->u.constant) + 1); + } else if (Z_TYPE(class_name->u.constant) == IS_STRING && + Z_STRVAL(class_name->u.constant)[0] == ':') { + Z_STRLEN(class_name->u.constant) -= 2; + memmove(Z_STRVAL(class_name->u.constant), Z_STRVAL(class_name->u.constant)+2, Z_STRLEN(class_name->u.constant)+1); + Z_STRVAL(class_name->u.constant) = erealloc( + Z_STRVAL(class_name->u.constant), + Z_STRLEN(class_name->u.constant) + 1); + } else if (CG(current_import)) { + if (Z_TYPE(class_name->u.constant) == IS_UNICODE) { + len = compound.u - Z_USTRVAL(class_name->u.constant); + lcname = zend_u_str_case_fold(Z_TYPE(class_name->u.constant), Z_UNIVAL(class_name->u.constant), len, 0, &lcname_len); + } else { + len = compound.s - Z_STRVAL(class_name->u.constant); + lcname = zend_u_str_case_fold(Z_TYPE(class_name->u.constant), Z_UNIVAL(class_name->u.constant), len , 0, &lcname_len); + } + if (zend_u_hash_find(CG(current_import), Z_TYPE(class_name->u.constant), lcname, lcname_len+1, (void**)&ns) == SUCCESS) { + tmp.op_type = IS_CONST; + tmp.u.constant = **ns; + zval_copy_ctor(&tmp.u.constant); + len += 2; + Z_UNILEN(class_name->u.constant) -= len; + if (Z_TYPE(class_name->u.constant) == IS_UNICODE) { + memmove(Z_USTRVAL(class_name->u.constant), Z_USTRVAL(class_name->u.constant)+len, UBYTES(Z_USTRLEN(class_name->u.constant)+1)); + } else { + memmove(Z_STRVAL(class_name->u.constant), Z_STRVAL(class_name->u.constant)+len, Z_STRLEN(class_name->u.constant)+1); + } + zend_do_build_namespace_name(&tmp, &tmp, class_name TSRMLS_CC); + *class_name = tmp; + } + efree(lcname.v); + } + } else if (CG(current_import) || CG(current_namespace)) { + lcname = zend_u_str_case_fold(Z_TYPE(class_name->u.constant), Z_UNIVAL(class_name->u.constant), Z_UNILEN(class_name->u.constant), 0, &lcname_len); + + if (CG(current_import) && + zend_u_hash_find(CG(current_import), Z_TYPE(class_name->u.constant), lcname, lcname_len+1, (void**)&ns) == SUCCESS) { + zval_dtor(&class_name->u.constant); + class_name->u.constant = **ns; + zval_copy_ctor(&class_name->u.constant); + } else if (CG(current_namespace)) { + zend_class_entry **pce; + + if (zend_u_hash_find(CG(class_table), Z_TYPE(class_name->u.constant), lcname, lcname_len+1, (void**)&pce) == SUCCESS && + (*pce)->type == ZEND_INTERNAL_CLASS) { + *fetch_type |= ZEND_FETCH_CLASS_RT_NS_CHECK; + } + tmp.op_type = IS_CONST; + tmp.u.constant = *CG(current_namespace); + zval_copy_ctor(&tmp.u.constant); + zend_do_build_namespace_name(&tmp, &tmp, class_name TSRMLS_CC); + *class_name = tmp; + } + efree(lcname.v); + } +} +/* }}} */ + void zend_do_fetch_class(znode *result, znode *class_name TSRMLS_DC) /* {{{ */ { long fetch_class_op_number; @@ -1564,16 +1679,18 @@ void zend_do_fetch_class(znode *result, znode *class_name TSRMLS_DC) /* {{{ */ opline->extended_value = fetch_type; zval_dtor(&class_name->u.constant); break; - default: + default: { + zend_resolve_class_name(class_name, &opline->extended_value TSRMLS_CC); opline->op2 = *class_name; break; + } } } else { opline->op2 = *class_name; } opline->result.u.var = get_temporary_variable(CG(active_op_array)); opline->result.u.EA.type = opline->extended_value; - opline->result.op_type = IS_CONST; /* FIXME: Hack so that INIT_FCALL_BY_NAME still knows this is a class */ + opline->result.op_type = IS_VAR; /* FIXME: Hack so that INIT_FCALL_BY_NAME still knows this is a class */ *result = opline->result; } /* }}} */ @@ -1607,11 +1724,26 @@ void zend_do_fetch_class_name(znode *result, znode *class_name_entry, znode *cla void zend_do_begin_class_member_function_call(znode *class_name, znode *method_name TSRMLS_DC) /* {{{ */ { + znode class_node; unsigned char *ptr = NULL; - zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); - + zend_op *opline; + ulong fetch_type; + + if (class_name->op_type == IS_CONST && + method_name->op_type == IS_CONST && + ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type(Z_TYPE(class_name->u.constant), Z_UNIVAL(class_name->u.constant), Z_UNILEN(class_name->u.constant))) { + fetch_type = ZEND_FETCH_CLASS_GLOBAL; + zend_resolve_class_name(class_name, &fetch_type TSRMLS_CC); + class_node = *class_name; + fetch_type |= ZEND_FETCH_CLASS_RT_NS_CHECK; + } else { + zend_do_fetch_class(&class_node, class_name TSRMLS_CC); + fetch_type = 0; + } + opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_INIT_STATIC_METHOD_CALL; - opline->op1 = *class_name; + opline->extended_value = fetch_type; + opline->op1 = class_node; opline->op2 = *method_name; if (opline->op2.op_type == IS_CONST) { @@ -1932,11 +2064,15 @@ void zend_do_try(znode *try_token TSRMLS_DC) /* {{{ */ } /* }}} */ -void zend_do_begin_catch(znode *try_token, znode *catch_class, znode *catch_var, zend_bool first_catch TSRMLS_DC) /* {{{ */ +void zend_do_begin_catch(znode *try_token, znode *class_name, znode *catch_var, znode *first_catch TSRMLS_DC) /* {{{ */ { - long catch_op_number = get_next_op_number(CG(active_op_array)); + long catch_op_number; zend_op *opline; + znode catch_class; + zend_do_fetch_class(&catch_class, class_name TSRMLS_CC); + + catch_op_number = get_next_op_number(CG(active_op_array)); if (catch_op_number > 0) { opline = &CG(active_op_array)->opcodes[catch_op_number-1]; if (opline->opcode == ZEND_FETCH_CLASS) { @@ -1944,9 +2080,13 @@ void zend_do_begin_catch(znode *try_token, znode *catch_class, znode *catch_var, } } + if (first_catch) { + first_catch->u.opline_num = catch_op_number; + } + opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_CATCH; - opline->op1 = *catch_class; + opline->op1 = catch_class; /* SET_UNUSED(opline->op1); */ /* FIXME: Define IS_CLASS or something like that */ opline->op2 = *catch_var; opline->op1.u.EA.type = 0; /* 1 means it's the last catch in the block */ @@ -2974,6 +3114,17 @@ void zend_do_begin_class_declaration(znode *class_token, znode *class_name, znod zend_error(E_COMPILE_ERROR, "Cannot use '%R' as class name as it is reserved", Z_TYPE(class_name->u.constant), Z_UNIVAL(class_name->u.constant)); } + if (CG(current_namespace)) { + znode tmp; + + tmp.u.constant = *CG(current_namespace); + zval_copy_ctor(&tmp.u.constant); + zend_do_build_namespace_name(&tmp, &tmp, class_name TSRMLS_CC); + class_name = &tmp; + efree(lcname.v); + lcname = zend_u_str_case_fold(Z_TYPE(class_name->u.constant), Z_UNIVAL(class_name->u.constant), Z_UNILEN(class_name->u.constant), 0, &lcname_len); + } + new_class_entry = emalloc(sizeof(zend_class_entry)); new_class_entry->type = ZEND_USER_CLASS; new_class_entry->name = Z_UNIVAL(class_name->u.constant); @@ -3091,11 +3242,13 @@ void zend_do_end_class_declaration(znode *class_token, znode *parent_token TSRML } /* }}} */ -void zend_do_implements_interface(znode *interface_znode TSRMLS_DC) /* {{{ */ +void zend_do_implements_interface(znode *interface_name TSRMLS_DC) /* {{{ */ { + znode interface_node; zend_op *opline; - switch (interface_znode->u.EA.type) { + zend_do_fetch_class(&interface_node, interface_name TSRMLS_CC); + switch (interface_node.u.EA.type) { case ZEND_FETCH_CLASS_SELF: zend_error(E_COMPILE_ERROR, "Cannot use 'self' as interface name as it is reserved"); break; @@ -3115,7 +3268,7 @@ void zend_do_implements_interface(znode *interface_znode TSRMLS_DC) /* {{{ */ opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_ADD_INTERFACE; opline->op1 = CG(implementing_class); - opline->op2 = *interface_znode; + opline->op2 = interface_node; opline->extended_value = CG(active_class_entry)->num_interfaces++; } /* }}} */ @@ -3506,13 +3659,18 @@ void zend_do_fetch_constant(znode *result, znode *constant_container, znode *con case ZEND_RT: if (constant_container || !zend_constant_ct_subst(result, &constant_name->u.constant TSRMLS_CC)) { - zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); + zend_op *opline; + znode class_node; + if (constant_container) { + zend_do_fetch_class(&class_node, constant_container TSRMLS_CC); + } + opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_FETCH_CONSTANT; opline->result.op_type = IS_TMP_VAR; opline->result.u.var = get_temporary_variable(CG(active_op_array)); if (constant_container) { - opline->op1 = *constant_container; + opline->op1 = class_node; } else { SET_UNUSED(opline->op1); } @@ -4686,6 +4844,132 @@ void zend_release_labels(TSRMLS_D) /* {{{ */ } /* }}} */ +void zend_do_build_namespace_name(znode *result, znode *prefix, znode *name TSRMLS_DC) /* {{{ */ +{ + int len; + + if (prefix) { + *result = *prefix; + } else { + result->op_type = IS_CONST; + Z_TYPE(result->u.constant) = ZEND_STR_TYPE; + Z_UNIVAL(result->u.constant) = NULL_ZSTR; + Z_UNILEN(result->u.constant) = 0; + } + len = Z_UNILEN(result->u.constant) + 2 + Z_UNILEN(name->u.constant); + if (UG(unicode)) { + Z_USTRVAL(result->u.constant) = eurealloc(Z_USTRVAL(result->u.constant), len + 1); + Z_USTRVAL(result->u.constant)[Z_USTRLEN(result->u.constant)] = ':'; + Z_USTRVAL(result->u.constant)[Z_USTRLEN(result->u.constant)+1] = ':'; + memcpy(Z_USTRVAL(result->u.constant)+Z_USTRLEN(result->u.constant)+2, + Z_USTRVAL(name->u.constant), + UBYTES(Z_USTRLEN(name->u.constant)+1)); + } else { + Z_USTRVAL(result->u.constant) = erealloc(Z_STRVAL(result->u.constant), len + 1); + Z_STRVAL(result->u.constant)[Z_STRLEN(result->u.constant)] = ':'; + Z_STRVAL(result->u.constant)[Z_STRLEN(result->u.constant)+1] = ':'; + memcpy(Z_STRVAL(result->u.constant)+Z_STRLEN(result->u.constant)+2, + Z_STRVAL(name->u.constant), + Z_USTRLEN(name->u.constant)+1); + } + Z_UNILEN(result->u.constant) = len; + zval_dtor(&name->u.constant); +} +/* }}} */ + +void zend_do_namespace(znode *name TSRMLS_DC) /* {{{ */ +{ + unsigned int lcname_len; + zstr lcname; + + if (CG(active_op_array)->last > 0) { + zend_error(E_COMPILE_ERROR, "Namespace declaration statement has to be the very first statement in the script"); + } + if (CG(current_namespace)) { + zend_error(E_COMPILE_ERROR, "Namespace cannot be declared twice"); + } + lcname = zend_u_str_case_fold(Z_TYPE(name->u.constant), Z_UNIVAL(name->u.constant), Z_UNILEN(name->u.constant), 0, &lcname_len); + if (((lcname_len == sizeof("self")-1) && + ZEND_U_EQUAL(Z_TYPE(name->u.constant), lcname, lcname_len, "self", sizeof("self")-1)) || + ((lcname_len == sizeof("parent")-1) && + ZEND_U_EQUAL(Z_TYPE(name->u.constant), lcname, lcname_len, "parent", sizeof("parent")-1))) { + zend_error(E_COMPILE_ERROR, "Cannot use '%R' as namespace name", Z_TYPE(name->u.constant), Z_UNIVAL(name->u.constant)); + } + efree(lcname.v); + + ALLOC_ZVAL(CG(current_namespace)); + *CG(current_namespace) = name->u.constant; +} +/* }}} */ + +void zend_do_import(znode *ns_name, znode *new_name TSRMLS_DC) /* {{{ */ +{ + unsigned int lcname_len; + zstr lcname; + zval *name, *ns, tmp; + + if (!CG(current_import)) { + CG(current_import) = emalloc(sizeof(HashTable)); + zend_u_hash_init(CG(current_import), 0, NULL, ZVAL_PTR_DTOR, 0, UG(unicode)); + } + + ALLOC_ZVAL(ns); + *ns = ns_name->u.constant; + if (new_name) { + name = &new_name->u.constant; + } else { + name = &tmp; + if (UG(unicode)) { + UChar *p = u_memrchr(Z_USTRVAL_P(ns), ':', Z_USTRLEN_P(ns)); + if (p) { + ZVAL_UNICODE(name, p+1, 1); + } else { + *name = *ns; + zval_copy_ctor(name); + } + } else { + char *p = zend_memrchr(Z_STRVAL_P(ns), ':', Z_STRLEN_P(ns)); + if (p) { + ZVAL_STRING(name, p+1, 1); + } else { + *name = *ns; + zval_copy_ctor(name); + } + } + } + + lcname = zend_u_str_case_fold(Z_TYPE_P(name), Z_UNIVAL_P(name), Z_UNILEN_P(name), 0, &lcname_len); + + if (((lcname_len == sizeof("self")-1) && + ZEND_U_EQUAL(Z_TYPE_P(name), lcname, lcname_len, "self", sizeof("self")-1)) || + ((lcname_len == sizeof("parent")-1) && + ZEND_U_EQUAL(Z_TYPE_P(name), lcname, lcname_len, "parent", sizeof("parent")-1))) { + zend_error(E_COMPILE_ERROR, "Cannot use '%R' as import name", Z_TYPE_P(name), Z_UNIVAL_P(name)); + } + + if (zend_u_hash_add(CG(current_import), Z_TYPE_P(name), lcname, lcname_len+1, &ns, sizeof(zval*), NULL) != SUCCESS) { + zend_error(E_COMPILE_ERROR, "Cannot reuse import name"); + } + efree(lcname.v); + zval_dtor(name); +} +/* }}} */ + +void zend_do_end_compilation(TSRMLS_D) /* {{{ */ +{ + if (CG(current_namespace)) { + zval_dtor(CG(current_namespace)); + efree(CG(current_namespace)); + CG(current_namespace) = NULL; + } + if (CG(current_import)) { + zend_hash_destroy(CG(current_import)); + efree(CG(current_import)); + CG(current_import) = NULL; + } +} +/* }}} */ + /* * Local variables: * tab-width: 4 diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index fa22d61867..69fd1571ea 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -411,7 +411,7 @@ int zend_do_verify_access_types(znode *current_access_type, znode *new_modifier) void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference, znode *fn_flags_znode TSRMLS_DC); void zend_do_end_function_declaration(znode *function_token TSRMLS_DC); void zend_do_receive_arg(zend_uchar op, znode *var, znode *offset, znode *initialization, znode *class_type, znode *varname, zend_bool pass_by_reference TSRMLS_DC); -int zend_do_begin_function_call(znode *function_name TSRMLS_DC); +int zend_do_begin_function_call(znode *function_name, zend_bool check_namespace TSRMLS_DC); void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC); void zend_do_clone(znode *result, znode *expr TSRMLS_DC); void zend_do_begin_dynamic_function_call(znode *function_name TSRMLS_DC); @@ -423,7 +423,7 @@ void zend_do_return(znode *expr, int do_end_vparse TSRMLS_DC); void zend_do_handle_exception(TSRMLS_D); void zend_do_try(znode *try_token TSRMLS_DC); -void zend_do_begin_catch(znode *try_token, znode *catch_class, znode *catch_var, zend_bool first_catch TSRMLS_DC); +void zend_do_begin_catch(znode *try_token, znode *catch_class, znode *catch_var, znode *first_catch TSRMLS_DC); void zend_do_end_catch(znode *try_token TSRMLS_DC); void zend_do_throw(znode *expr TSRMLS_DC); @@ -519,6 +519,11 @@ void zend_do_ticks(TSRMLS_D); void zend_do_abstract_method(znode *function_name, znode *modifiers, znode *body TSRMLS_DC); +void zend_do_build_namespace_name(znode *result, znode *prefix, znode *name TSRMLS_DC); +void zend_do_namespace(znode *name TSRMLS_DC); +void zend_do_import(znode *name, znode *new_name TSRMLS_DC); +void zend_do_end_compilation(TSRMLS_D); + ZEND_API void function_add_ref(zend_function *function TSRMLS_DC); void zend_do_normalization(znode *result, znode *str TSRMLS_DC); @@ -628,6 +633,7 @@ int zendlex(znode *zendlval TSRMLS_DC); #define ZEND_FETCH_CLASS_INTERFACE 6 #define ZEND_FETCH_CLASS_FLAGS 0xF0 #define ZEND_FETCH_CLASS_NO_NORMALIZE 0x10 +#define ZEND_FETCH_CLASS_RT_NS_CHECK 0x20 #define ZEND_FETCH_CLASS_NO_AUTOLOAD 0x80 /* variable parsing type (compile-time) */ diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index ad8c2fdc44..4001d8424f 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -1123,7 +1123,7 @@ ZEND_API int zend_u_lookup_class_ex(zend_uchar type, zstr name, int name_length, zval *retval_ptr = NULL; int retval; unsigned int lc_name_len; - zstr lc_name; + zstr lc_name, lc_free; zval *exception; char dummy = 1; zend_fcall_info fcall_info; @@ -1134,15 +1134,26 @@ ZEND_API int zend_u_lookup_class_ex(zend_uchar type, zstr name, int name_length, } if (do_normalize) { - lc_name = zend_u_str_case_fold(type, name, name_length, 1, &lc_name_len); + lc_free = lc_name = zend_u_str_case_fold(type, name, name_length, 1, &lc_name_len); } else { lc_name = name; lc_name_len = name_length; } + if (type == IS_UNICODE && + lc_name.u[0] == ':' && + lc_name.u[1] == ':') { + lc_name.u += 2; + lc_name_len -= 2; + } else if (type == IS_STRING && + lc_name.s[0] == ':' && + lc_name.s[1] == ':') { + lc_name.s += 2; + lc_name_len -= 2; + } if (zend_u_hash_find(EG(class_table), type, lc_name, lc_name_len+1, (void **) ce) == SUCCESS) { if (do_normalize) { - efree(lc_name.v); + efree(lc_free.v); } return SUCCESS; } @@ -1152,7 +1163,7 @@ ZEND_API int zend_u_lookup_class_ex(zend_uchar type, zstr name, int name_length, */ if (!use_autoload || zend_is_compiling(TSRMLS_C)) { if (do_normalize) { - efree(lc_name.v); + efree(lc_free.v); } return FAILURE; } @@ -1164,7 +1175,7 @@ ZEND_API int zend_u_lookup_class_ex(zend_uchar type, zstr name, int name_length, if (zend_u_hash_add(EG(in_autoload), type, lc_name, lc_name_len+1, (void**)&dummy, sizeof(char), NULL) == FAILURE) { if (do_normalize) { - efree(lc_name.v); + efree(lc_free.v); } return FAILURE; } @@ -1208,14 +1219,14 @@ ZEND_API int zend_u_lookup_class_ex(zend_uchar type, zstr name, int name_length, if (retval == FAILURE) { EG(exception) = exception; if (do_normalize) { - efree(lc_name.v); + efree(lc_free.v); } return FAILURE; } if (EG(exception) && exception) { if (do_normalize) { - efree(lc_name.v); + efree(lc_free.v); } zend_error(E_ERROR, "Function %s(%R) threw an exception of type '%v'", ZEND_AUTOLOAD_FUNC_NAME, type, name, Z_OBJCE_P(EG(exception))->name); return FAILURE; @@ -1229,7 +1240,7 @@ ZEND_API int zend_u_lookup_class_ex(zend_uchar type, zstr name, int name_length, retval = zend_u_hash_find(EG(class_table), type, lc_name, lc_name_len + 1, (void **) ce); if (do_normalize) { - efree(lc_name.v); + efree(lc_free.v); } return retval; } @@ -1636,6 +1647,7 @@ ZEND_API zend_class_entry *zend_u_fetch_class(zend_uchar type, zstr class_name, zend_class_entry **pce; int use_autoload = (fetch_type & ZEND_FETCH_CLASS_NO_AUTOLOAD) ? 0 : 1; int do_normalize = (fetch_type & ZEND_FETCH_CLASS_NO_NORMALIZE) ? 0 : 1; + int rt_ns_check = (fetch_type & ZEND_FETCH_CLASS_RT_NS_CHECK) ? 1 : 0; zstr lcname = class_name; fetch_type = fetch_type & ~ZEND_FETCH_CLASS_FLAGS; @@ -1672,6 +1684,36 @@ check_fetch_type: } if (zend_u_lookup_class_ex(type, lcname, class_name_len, use_autoload, do_normalize, &pce TSRMLS_CC)==FAILURE) { + if (rt_ns_check) { + /* Check if we have internal class with the same name */ + zstr php_name; + + if (type == IS_UNICODE) { + php_name.u = u_memrchr(lcname.u, ':', class_name_len); + if (php_name.u) { + php_name.u++; + if (zend_u_lookup_class_ex(type, php_name, class_name_len-(php_name.u-lcname.u), 0, do_normalize, &pce TSRMLS_CC)==SUCCESS && + (*pce)->type == ZEND_INTERNAL_CLASS) { + if (lcname.v != class_name.v) { + efree(lcname.v); + } + return *pce; + } + } + } else { + php_name.s = zend_memrchr(lcname.s, ':', class_name_len); + if (php_name.s) { + php_name.s++; + if (zend_u_lookup_class_ex(type, php_name, class_name_len-(php_name.s-lcname.s), 0, do_normalize, &pce TSRMLS_CC)==SUCCESS && + (*pce)->type == ZEND_INTERNAL_CLASS) { + if (lcname.v != class_name.v) { + efree(lcname.v); + } + return *pce; + } + } + } + } if (use_autoload) { if (fetch_type == ZEND_FETCH_CLASS_INTERFACE) { zend_error(E_ERROR, "Interface '%R' not found", type, class_name); diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index 40e096c73e..95b5ea94f8 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -138,6 +138,9 @@ struct _zend_compiler_globals { HashTable *labels; zend_stack labels_stack; + zval *current_namespace; + HashTable *current_import; + #ifdef ZTS HashTable **static_members; int last_static_member; diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 6846384078..392e6325d1 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -146,11 +146,14 @@ %token T_PAAMAYIM_NEKUDOTAYIM %token T_BINARY_DOUBLE %token T_BINARY_HEREDOC +%token T_NAMESPACE +%token T_IMPORT +%token T_NS_C %% /* Rules */ start: - top_statement_list + top_statement_list { zend_do_end_compilation(TSRMLS_C); } ; top_statement_list: @@ -158,12 +161,19 @@ top_statement_list: | /* empty */ ; +namespace_name: + T_STRING { $$ = $1; } + | namespace_name T_PAAMAYIM_NEKUDOTAYIM T_STRING { zend_do_build_namespace_name(&$$, &$1, &$3 TSRMLS_CC); } +; top_statement: statement | function_declaration_statement { zend_do_early_binding(TSRMLS_C); } | class_declaration_statement { zend_do_early_binding(TSRMLS_C); } - | T_HALT_COMPILER '(' ')' ';' { zend_do_halt_compiler_register(TSRMLS_C); YYACCEPT; } + | T_HALT_COMPILER '(' ')' ';' { zend_do_halt_compiler_register(TSRMLS_C); YYACCEPT; } + | T_NAMESPACE namespace_name ';' { zend_do_namespace(&$2 TSRMLS_CC); } + | T_IMPORT namespace_name ';' { zend_do_import(&$2, NULL TSRMLS_CC); } + | T_IMPORT namespace_name T_AS T_STRING ';' { zend_do_import(&$2, &$4 TSRMLS_CC); } ; @@ -229,7 +239,7 @@ unticked_statement: | T_TRY { zend_do_try(&$1 TSRMLS_CC); } '{' inner_statement_list '}' T_CATCH '(' { zend_initialize_try_catch_element(&$1 TSRMLS_CC); } fully_qualified_class_name { zend_do_first_catch(&$7 TSRMLS_CC); } - T_VARIABLE ')' { zend_do_begin_catch(&$1, &$9, &$11, 1 TSRMLS_CC); } + T_VARIABLE ')' { zend_do_begin_catch(&$1, &$9, &$11, &$7 TSRMLS_CC); } '{' inner_statement_list '}' { zend_do_end_catch(&$1 TSRMLS_CC); } additional_catches { zend_do_mark_last_catch(&$7, &$18 TSRMLS_CC); } | T_THROW expr ';' { zend_do_throw(&$2 TSRMLS_CC); } @@ -249,7 +259,7 @@ non_empty_additional_catches: additional_catch: - T_CATCH '(' fully_qualified_class_name { $$.u.opline_num = get_next_op_number(CG(active_op_array)); } T_VARIABLE ')' { zend_do_begin_catch(&$1, &$3, &$5, 0 TSRMLS_CC); } '{' inner_statement_list '}' { zend_do_end_catch(&$1 TSRMLS_CC); } + T_CATCH '(' fully_qualified_class_name { $$.u.opline_num = get_next_op_number(CG(active_op_array)); } T_VARIABLE ')' { zend_do_begin_catch(&$1, &$3, &$5, NULL TSRMLS_CC); } '{' inner_statement_list '}' { zend_do_end_catch(&$1 TSRMLS_CC); } ; @@ -312,7 +322,7 @@ class_entry_type: extends_from: /* empty */ { $$.op_type = IS_UNUSED; } - | T_EXTENDS fully_qualified_class_name { $$ = $2; } + | T_EXTENDS fully_qualified_class_name { zend_do_fetch_class(&$$, &$2 TSRMLS_CC); } ; interface_entry: @@ -630,9 +640,12 @@ expr_without_variable: ; function_call: - T_STRING '(' { $2.u.opline_num = zend_do_begin_function_call(&$1 TSRMLS_CC); } + T_STRING '(' { $2.u.opline_num = zend_do_begin_function_call(&$1, 1 TSRMLS_CC); } function_call_parameter_list ')' { zend_do_end_function_call(&$1, &$$, &$4, 0, $2.u.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); } + | T_PAAMAYIM_NEKUDOTAYIM T_STRING '(' { $3.u.opline_num = zend_do_begin_function_call(&$2, 0 TSRMLS_CC); } + function_call_parameter_list + ')' { zend_do_end_function_call(&$2, &$$, &$5, 0, $3.u.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} | fully_qualified_class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING '(' { zend_do_begin_class_member_function_call(&$1, &$3 TSRMLS_CC); } function_call_parameter_list ')' { zend_do_end_function_call(NULL, &$$, &$6, 1, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} @@ -645,11 +658,14 @@ function_call: ; fully_qualified_class_name: - T_STRING { zend_do_fetch_class(&$$, &$1 TSRMLS_CC); } + T_STRING { $$ = $1; } + | T_PAAMAYIM_NEKUDOTAYIM T_STRING { zend_do_build_namespace_name(&$$, NULL, &$2 TSRMLS_CC); } + | fully_qualified_class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING { zend_do_build_namespace_name(&$$, &$1, &$3 TSRMLS_CC); } ; + class_name_reference: - T_STRING { zend_do_fetch_class(&$$, &$1 TSRMLS_CC); } + fully_qualified_class_name { zend_do_fetch_class(&$$, &$1 TSRMLS_CC); } | dynamic_class_name_reference { zend_do_end_variable_parse(BP_VAR_R, 0 TSRMLS_CC); zend_do_fetch_class(&$$, &$1 TSRMLS_CC); } ; @@ -694,6 +710,7 @@ common_scalar: | T_CLASS_C { $$ = $1; } | T_METHOD_C { $$ = $1; } | T_FUNC_C { $$ = $1; } + | T_NS_C { $$ = $1; } ; diff --git a/Zend/zend_language_scanner.l b/Zend/zend_language_scanner.l index e252411c13..e3704f9fa9 100644 --- a/Zend/zend_language_scanner.l +++ b/Zend/zend_language_scanner.l @@ -1699,6 +1699,14 @@ HEREDOC_CHARS ("{"*([^$\n\r\\{]|("\\"[^\n\r]))|{HEREDOC_LITERAL_DOLLAR}|({ return T_REQUIRE_ONCE; } +"namespace" { + return T_NAMESPACE; +} + +"import" { + return T_IMPORT; +} + "use" { return T_USE; } @@ -2072,6 +2080,16 @@ HEREDOC_CHARS ("{"*([^$\n\r\\{]|("\\"[^\n\r]))|{HEREDOC_LITERAL_DOLLAR}|({ return T_FILE; } +"__NAMESPACE__" { + if (CG(current_namespace)) { + *zendlval = *CG(current_namespace); + zval_copy_ctor(zendlval); + } else { + ZVAL_EMPTY_TEXT(zendlval); + } + return T_NS_C; +} + (([^<]|"<"[^?%s<]){1,400})|"op1.u.var).class_entry; + if (OP1_TYPE == IS_CONST && OP2_TYPE == IS_CONST) { + /* try a function in namespace */ + zstr fname, lcname; + unsigned int len, lcname_len; + + len = Z_UNILEN(opline->op1.u.constant) + 2 + Z_UNILEN(opline->op2.u.constant); + if (UG(unicode)) { + fname.u = eumalloc(len + 1); + memcpy(fname.u, Z_USTRVAL(opline->op1.u.constant), UBYTES(Z_USTRLEN(opline->op1.u.constant))); + fname.u[Z_USTRLEN(opline->op1.u.constant)] = ':'; + fname.u[Z_USTRLEN(opline->op1.u.constant)+1] = ':'; + memcpy(fname.u+Z_USTRLEN(opline->op1.u.constant)+2, + Z_USTRVAL(opline->op2.u.constant), + UBYTES(Z_USTRLEN(opline->op2.u.constant)+1)); + lcname = zend_u_str_case_fold(IS_UNICODE, fname, len, 1, &lcname_len); + } else { + fname.s = emalloc(len + 1); + memcpy(fname.s, Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant)); + fname.s[Z_STRLEN(opline->op1.u.constant)] = ':'; + fname.s[Z_STRLEN(opline->op1.u.constant)+1] = ':'; + memcpy(fname.s+Z_STRLEN(opline->op1.u.constant)+2, + Z_STRVAL(opline->op2.u.constant), + Z_STRLEN(opline->op2.u.constant)+1); + lcname = zend_u_str_case_fold(IS_STRING, fname, len, 1, &lcname_len); + } + efree(fname.v); + + if (zend_u_hash_find(EG(function_table), ZEND_STR_TYPE, lcname, lcname_len+1, (void **) &EX(fbc))==SUCCESS) { + efree(lcname.v); + EX(object) = NULL; + ZEND_VM_NEXT_OPCODE(); + } + efree(lcname.v); + + /* no function found. try a static method in class */ + ce = zend_u_fetch_class(Z_TYPE(opline->op1.u.constant), Z_UNIVAL(opline->op1.u.constant), Z_UNILEN(opline->op1.u.constant), opline->extended_value TSRMLS_CC); + } else { + ce = EX_T(opline->op1.u.var).class_entry; + } if(OP2_TYPE != IS_UNUSED) { zstr function_name_strval; unsigned int function_name_strlen; @@ -1869,10 +1907,38 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV) function_name_strval = Z_UNIVAL_P(function_name); function_name_strlen = Z_UNILEN_P(function_name); - lcname = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_UNIVAL_P(function_name), function_name_strlen, 1, &lcname_len); + if (OP2_TYPE != IS_CONST && + ((Z_TYPE_P(function_name) == IS_UNICODE && + Z_USTRVAL_P(function_name)[0] == ':' && + Z_USTRVAL_P(function_name)[1] == ':') || + (Z_TYPE_P(function_name) == IS_STRING && + Z_STRVAL_P(function_name)[0] == ':' && + Z_STRVAL_P(function_name)[1] == ':'))) { + if (Z_TYPE_P(function_name) == IS_UNICODE) { + lcname = zend_u_str_case_fold(IS_UNICODE, (zstr)(Z_USTRVAL_P(function_name)+2), function_name_strlen-2, 1, &lcname_len); + } else { + lcname = zend_u_str_case_fold(IS_STRING, (zstr)(Z_STRVAL_P(function_name)+2), function_name_strlen-2, 1, &lcname_len); + } + } else { + lcname = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_UNIVAL_P(function_name), function_name_strlen, 1, &lcname_len); + } if (zend_u_hash_find(EG(function_table), Z_TYPE_P(function_name), lcname, lcname_len+1, (void **) &function)==FAILURE) { efree(lcname.v); - zend_error_noreturn(E_ERROR, "Call to undefined function %R()", Z_TYPE_P(function_name), function_name_strval); + + if (OP2_TYPE == IS_CONST && opline->op1.op_type == IS_CONST) { + if (Z_TYPE_P(function_name) == IS_UNICODE) { + lcname = zend_u_str_case_fold(IS_UNICODE, (zstr)(Z_USTRVAL_P(function_name)+Z_LVAL(opline->op1.u.constant)), function_name_strlen-Z_LVAL(opline->op1.u.constant), 1, &lcname_len); + } else { + lcname = zend_u_str_case_fold(IS_STRING, (zstr)(Z_STRVAL_P(function_name)+Z_LVAL(opline->op1.u.constant)), function_name_strlen-Z_LVAL(opline->op1.u.constant), 1, &lcname_len); + } + if (zend_u_hash_find(EG(function_table), Z_TYPE_P(function_name), lcname, lcname_len+1, (void **) &function)==FAILURE || + function->type != ZEND_INTERNAL_FUNCTION) { + efree(lcname.v); + zend_error_noreturn(E_ERROR, "Call to undefined function %R()", Z_TYPE_P(function_name), function_name_strval); + } + } else { + zend_error_noreturn(E_ERROR, "Call to undefined function %R()", Z_TYPE_P(function_name), function_name_strval); + } } efree(lcname.v); @@ -2638,7 +2704,7 @@ ZEND_VM_HANDLER(110, ZEND_CLONE, CONST|TMP|VAR|UNUSED|CV, ANY) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(99, ZEND_FETCH_CONSTANT, CONST|UNUSED, CONST) +ZEND_VM_HANDLER(99, ZEND_FETCH_CONSTANT, VAR|UNUSED, CONST) { zend_op *opline = EX(opline); zend_class_entry *ce = NULL; diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 704f2efb3a..1b7d0c5515 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -667,69 +667,6 @@ static int ZEND_FETCH_CLASS_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) ZEND_VM_NEXT_OPCODE(); } -static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - zend_op *opline = EX(opline); - zval *function_name; - zend_class_entry *ce; - - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); - - ce = EX_T(opline->op1.u.var).class_entry; - if(IS_CONST != IS_UNUSED) { - zstr function_name_strval; - unsigned int function_name_strlen; - zend_bool is_const = (IS_CONST == IS_CONST); - - - if (is_const) { - function_name_strval = Z_UNIVAL(opline->op2.u.constant); - function_name_strlen = Z_UNILEN(opline->op2.u.constant); - } else { - function_name = &opline->op2.u.constant; - - if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { - zend_error_noreturn(E_ERROR, "Function name must be a string"); - } - function_name_strval = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_UNIVAL_P(function_name), Z_UNILEN_P(function_name), 1, &function_name_strlen); - } - - EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); - - if (!is_const) { - efree(function_name_strval.v); - - } - } else { - if(!ce->constructor) { - zend_error_noreturn(E_ERROR, "Can not call constructor"); - } - if (EG(This) && Z_OBJCE_P(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { - zend_error(E_COMPILE_ERROR, "Cannot call private %v::__construct()", ce->name); - } - EX(fbc) = ce->constructor; - } - - if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { - EX(object) = NULL; - } else { - if (IS_CONST != IS_UNUSED && - EG(This) && - Z_OBJ_HT_P(EG(This))->get_class_entry && - !instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) { - /* We are calling method of the other (incompatible) class, - but passing $this. This is done for compatibility with php-4. */ - zend_error(E_STRICT, "Non-static method %v::%v() should not be called statically, assuming $this from incompatible context", EX(fbc)->common.scope->name, EX(fbc)->common.function_name); - - } - if ((EX(object) = EG(This))) { - EX(object)->refcount++; - } - } - - ZEND_VM_NEXT_OPCODE(); -} - static int ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -753,10 +690,38 @@ static int ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) function_name_strval = Z_UNIVAL_P(function_name); function_name_strlen = Z_UNILEN_P(function_name); - lcname = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_UNIVAL_P(function_name), function_name_strlen, 1, &lcname_len); + if (IS_CONST != IS_CONST && + ((Z_TYPE_P(function_name) == IS_UNICODE && + Z_USTRVAL_P(function_name)[0] == ':' && + Z_USTRVAL_P(function_name)[1] == ':') || + (Z_TYPE_P(function_name) == IS_STRING && + Z_STRVAL_P(function_name)[0] == ':' && + Z_STRVAL_P(function_name)[1] == ':'))) { + if (Z_TYPE_P(function_name) == IS_UNICODE) { + lcname = zend_u_str_case_fold(IS_UNICODE, (zstr)(Z_USTRVAL_P(function_name)+2), function_name_strlen-2, 1, &lcname_len); + } else { + lcname = zend_u_str_case_fold(IS_STRING, (zstr)(Z_STRVAL_P(function_name)+2), function_name_strlen-2, 1, &lcname_len); + } + } else { + lcname = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_UNIVAL_P(function_name), function_name_strlen, 1, &lcname_len); + } if (zend_u_hash_find(EG(function_table), Z_TYPE_P(function_name), lcname, lcname_len+1, (void **) &function)==FAILURE) { efree(lcname.v); - zend_error_noreturn(E_ERROR, "Call to undefined function %R()", Z_TYPE_P(function_name), function_name_strval); + + if (IS_CONST == IS_CONST && opline->op1.op_type == IS_CONST) { + if (Z_TYPE_P(function_name) == IS_UNICODE) { + lcname = zend_u_str_case_fold(IS_UNICODE, (zstr)(Z_USTRVAL_P(function_name)+Z_LVAL(opline->op1.u.constant)), function_name_strlen-Z_LVAL(opline->op1.u.constant), 1, &lcname_len); + } else { + lcname = zend_u_str_case_fold(IS_STRING, (zstr)(Z_STRVAL_P(function_name)+Z_LVAL(opline->op1.u.constant)), function_name_strlen-Z_LVAL(opline->op1.u.constant), 1, &lcname_len); + } + if (zend_u_hash_find(EG(function_table), Z_TYPE_P(function_name), lcname, lcname_len+1, (void **) &function)==FAILURE || + function->type != ZEND_INTERNAL_FUNCTION) { + efree(lcname.v); + zend_error_noreturn(E_ERROR, "Call to undefined function %R()", Z_TYPE_P(function_name), function_name_strval); + } + } else { + zend_error_noreturn(E_ERROR, "Call to undefined function %R()", Z_TYPE_P(function_name), function_name_strval); + } } efree(lcname.v); @@ -888,69 +853,6 @@ static int ZEND_FETCH_CLASS_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) ZEND_VM_NEXT_OPCODE(); } -static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - zend_op *opline = EX(opline); - zval *function_name; - zend_class_entry *ce; - - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); - - ce = EX_T(opline->op1.u.var).class_entry; - if(IS_TMP_VAR != IS_UNUSED) { - zstr function_name_strval; - unsigned int function_name_strlen; - zend_bool is_const = (IS_TMP_VAR == IS_CONST); - zend_free_op free_op2; - - if (is_const) { - function_name_strval = Z_UNIVAL(opline->op2.u.constant); - function_name_strlen = Z_UNILEN(opline->op2.u.constant); - } else { - function_name = _get_zval_ptr_tmp(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); - - if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { - zend_error_noreturn(E_ERROR, "Function name must be a string"); - } - function_name_strval = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_UNIVAL_P(function_name), Z_UNILEN_P(function_name), 1, &function_name_strlen); - } - - EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); - - if (!is_const) { - efree(function_name_strval.v); - zval_dtor(free_op2.var); - } - } else { - if(!ce->constructor) { - zend_error_noreturn(E_ERROR, "Can not call constructor"); - } - if (EG(This) && Z_OBJCE_P(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { - zend_error(E_COMPILE_ERROR, "Cannot call private %v::__construct()", ce->name); - } - EX(fbc) = ce->constructor; - } - - if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { - EX(object) = NULL; - } else { - if (IS_TMP_VAR != IS_UNUSED && - EG(This) && - Z_OBJ_HT_P(EG(This))->get_class_entry && - !instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) { - /* We are calling method of the other (incompatible) class, - but passing $this. This is done for compatibility with php-4. */ - zend_error(E_STRICT, "Non-static method %v::%v() should not be called statically, assuming $this from incompatible context", EX(fbc)->common.scope->name, EX(fbc)->common.function_name); - - } - if ((EX(object) = EG(This))) { - EX(object)->refcount++; - } - } - - ZEND_VM_NEXT_OPCODE(); -} - static int ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -974,10 +876,38 @@ static int ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) function_name_strval = Z_UNIVAL_P(function_name); function_name_strlen = Z_UNILEN_P(function_name); - lcname = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_UNIVAL_P(function_name), function_name_strlen, 1, &lcname_len); + if (IS_TMP_VAR != IS_CONST && + ((Z_TYPE_P(function_name) == IS_UNICODE && + Z_USTRVAL_P(function_name)[0] == ':' && + Z_USTRVAL_P(function_name)[1] == ':') || + (Z_TYPE_P(function_name) == IS_STRING && + Z_STRVAL_P(function_name)[0] == ':' && + Z_STRVAL_P(function_name)[1] == ':'))) { + if (Z_TYPE_P(function_name) == IS_UNICODE) { + lcname = zend_u_str_case_fold(IS_UNICODE, (zstr)(Z_USTRVAL_P(function_name)+2), function_name_strlen-2, 1, &lcname_len); + } else { + lcname = zend_u_str_case_fold(IS_STRING, (zstr)(Z_STRVAL_P(function_name)+2), function_name_strlen-2, 1, &lcname_len); + } + } else { + lcname = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_UNIVAL_P(function_name), function_name_strlen, 1, &lcname_len); + } if (zend_u_hash_find(EG(function_table), Z_TYPE_P(function_name), lcname, lcname_len+1, (void **) &function)==FAILURE) { efree(lcname.v); - zend_error_noreturn(E_ERROR, "Call to undefined function %R()", Z_TYPE_P(function_name), function_name_strval); + + if (IS_TMP_VAR == IS_CONST && opline->op1.op_type == IS_CONST) { + if (Z_TYPE_P(function_name) == IS_UNICODE) { + lcname = zend_u_str_case_fold(IS_UNICODE, (zstr)(Z_USTRVAL_P(function_name)+Z_LVAL(opline->op1.u.constant)), function_name_strlen-Z_LVAL(opline->op1.u.constant), 1, &lcname_len); + } else { + lcname = zend_u_str_case_fold(IS_STRING, (zstr)(Z_STRVAL_P(function_name)+Z_LVAL(opline->op1.u.constant)), function_name_strlen-Z_LVAL(opline->op1.u.constant), 1, &lcname_len); + } + if (zend_u_hash_find(EG(function_table), Z_TYPE_P(function_name), lcname, lcname_len+1, (void **) &function)==FAILURE || + function->type != ZEND_INTERNAL_FUNCTION) { + efree(lcname.v); + zend_error_noreturn(E_ERROR, "Call to undefined function %R()", Z_TYPE_P(function_name), function_name_strval); + } + } else { + zend_error_noreturn(E_ERROR, "Call to undefined function %R()", Z_TYPE_P(function_name), function_name_strval); + } } efree(lcname.v); @@ -1024,69 +954,6 @@ static int ZEND_FETCH_CLASS_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) ZEND_VM_NEXT_OPCODE(); } -static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - zend_op *opline = EX(opline); - zval *function_name; - zend_class_entry *ce; - - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); - - ce = EX_T(opline->op1.u.var).class_entry; - if(IS_VAR != IS_UNUSED) { - zstr function_name_strval; - unsigned int function_name_strlen; - zend_bool is_const = (IS_VAR == IS_CONST); - zend_free_op free_op2; - - if (is_const) { - function_name_strval = Z_UNIVAL(opline->op2.u.constant); - function_name_strlen = Z_UNILEN(opline->op2.u.constant); - } else { - function_name = _get_zval_ptr_var(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); - - if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { - zend_error_noreturn(E_ERROR, "Function name must be a string"); - } - function_name_strval = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_UNIVAL_P(function_name), Z_UNILEN_P(function_name), 1, &function_name_strlen); - } - - EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); - - if (!is_const) { - efree(function_name_strval.v); - if (free_op2.var) {zval_ptr_dtor(&free_op2.var);}; - } - } else { - if(!ce->constructor) { - zend_error_noreturn(E_ERROR, "Can not call constructor"); - } - if (EG(This) && Z_OBJCE_P(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { - zend_error(E_COMPILE_ERROR, "Cannot call private %v::__construct()", ce->name); - } - EX(fbc) = ce->constructor; - } - - if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { - EX(object) = NULL; - } else { - if (IS_VAR != IS_UNUSED && - EG(This) && - Z_OBJ_HT_P(EG(This))->get_class_entry && - !instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) { - /* We are calling method of the other (incompatible) class, - but passing $this. This is done for compatibility with php-4. */ - zend_error(E_STRICT, "Non-static method %v::%v() should not be called statically, assuming $this from incompatible context", EX(fbc)->common.scope->name, EX(fbc)->common.function_name); - - } - if ((EX(object) = EG(This))) { - EX(object)->refcount++; - } - } - - ZEND_VM_NEXT_OPCODE(); -} - static int ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -1110,10 +977,38 @@ static int ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) function_name_strval = Z_UNIVAL_P(function_name); function_name_strlen = Z_UNILEN_P(function_name); - lcname = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_UNIVAL_P(function_name), function_name_strlen, 1, &lcname_len); + if (IS_VAR != IS_CONST && + ((Z_TYPE_P(function_name) == IS_UNICODE && + Z_USTRVAL_P(function_name)[0] == ':' && + Z_USTRVAL_P(function_name)[1] == ':') || + (Z_TYPE_P(function_name) == IS_STRING && + Z_STRVAL_P(function_name)[0] == ':' && + Z_STRVAL_P(function_name)[1] == ':'))) { + if (Z_TYPE_P(function_name) == IS_UNICODE) { + lcname = zend_u_str_case_fold(IS_UNICODE, (zstr)(Z_USTRVAL_P(function_name)+2), function_name_strlen-2, 1, &lcname_len); + } else { + lcname = zend_u_str_case_fold(IS_STRING, (zstr)(Z_STRVAL_P(function_name)+2), function_name_strlen-2, 1, &lcname_len); + } + } else { + lcname = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_UNIVAL_P(function_name), function_name_strlen, 1, &lcname_len); + } if (zend_u_hash_find(EG(function_table), Z_TYPE_P(function_name), lcname, lcname_len+1, (void **) &function)==FAILURE) { efree(lcname.v); - zend_error_noreturn(E_ERROR, "Call to undefined function %R()", Z_TYPE_P(function_name), function_name_strval); + + if (IS_VAR == IS_CONST && opline->op1.op_type == IS_CONST) { + if (Z_TYPE_P(function_name) == IS_UNICODE) { + lcname = zend_u_str_case_fold(IS_UNICODE, (zstr)(Z_USTRVAL_P(function_name)+Z_LVAL(opline->op1.u.constant)), function_name_strlen-Z_LVAL(opline->op1.u.constant), 1, &lcname_len); + } else { + lcname = zend_u_str_case_fold(IS_STRING, (zstr)(Z_STRVAL_P(function_name)+Z_LVAL(opline->op1.u.constant)), function_name_strlen-Z_LVAL(opline->op1.u.constant), 1, &lcname_len); + } + if (zend_u_hash_find(EG(function_table), Z_TYPE_P(function_name), lcname, lcname_len+1, (void **) &function)==FAILURE || + function->type != ZEND_INTERNAL_FUNCTION) { + efree(lcname.v); + zend_error_noreturn(E_ERROR, "Call to undefined function %R()", Z_TYPE_P(function_name), function_name_strval); + } + } else { + zend_error_noreturn(E_ERROR, "Call to undefined function %R()", Z_TYPE_P(function_name), function_name_strval); + } } efree(lcname.v); @@ -1159,69 +1054,6 @@ static int ZEND_FETCH_CLASS_SPEC_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) ZEND_VM_NEXT_OPCODE(); } -static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - zend_op *opline = EX(opline); - zval *function_name; - zend_class_entry *ce; - - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); - - ce = EX_T(opline->op1.u.var).class_entry; - if(IS_UNUSED != IS_UNUSED) { - zstr function_name_strval; - unsigned int function_name_strlen; - zend_bool is_const = (IS_UNUSED == IS_CONST); - - - if (is_const) { - function_name_strval = Z_UNIVAL(opline->op2.u.constant); - function_name_strlen = Z_UNILEN(opline->op2.u.constant); - } else { - function_name = NULL; - - if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { - zend_error_noreturn(E_ERROR, "Function name must be a string"); - } - function_name_strval = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_UNIVAL_P(function_name), Z_UNILEN_P(function_name), 1, &function_name_strlen); - } - - EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); - - if (!is_const) { - efree(function_name_strval.v); - - } - } else { - if(!ce->constructor) { - zend_error_noreturn(E_ERROR, "Can not call constructor"); - } - if (EG(This) && Z_OBJCE_P(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { - zend_error(E_COMPILE_ERROR, "Cannot call private %v::__construct()", ce->name); - } - EX(fbc) = ce->constructor; - } - - if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { - EX(object) = NULL; - } else { - if (IS_UNUSED != IS_UNUSED && - EG(This) && - Z_OBJ_HT_P(EG(This))->get_class_entry && - !instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) { - /* We are calling method of the other (incompatible) class, - but passing $this. This is done for compatibility with php-4. */ - zend_error(E_STRICT, "Non-static method %v::%v() should not be called statically, assuming $this from incompatible context", EX(fbc)->common.scope->name, EX(fbc)->common.function_name); - - } - if ((EX(object) = EG(This))) { - EX(object)->refcount++; - } - } - - ZEND_VM_NEXT_OPCODE(); -} - static int ZEND_FETCH_CLASS_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -1252,69 +1084,6 @@ static int ZEND_FETCH_CLASS_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) ZEND_VM_NEXT_OPCODE(); } -static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - zend_op *opline = EX(opline); - zval *function_name; - zend_class_entry *ce; - - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); - - ce = EX_T(opline->op1.u.var).class_entry; - if(IS_CV != IS_UNUSED) { - zstr function_name_strval; - unsigned int function_name_strlen; - zend_bool is_const = (IS_CV == IS_CONST); - - - if (is_const) { - function_name_strval = Z_UNIVAL(opline->op2.u.constant); - function_name_strlen = Z_UNILEN(opline->op2.u.constant); - } else { - function_name = _get_zval_ptr_cv(&opline->op2, EX(Ts), BP_VAR_R TSRMLS_CC); - - if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { - zend_error_noreturn(E_ERROR, "Function name must be a string"); - } - function_name_strval = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_UNIVAL_P(function_name), Z_UNILEN_P(function_name), 1, &function_name_strlen); - } - - EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); - - if (!is_const) { - efree(function_name_strval.v); - - } - } else { - if(!ce->constructor) { - zend_error_noreturn(E_ERROR, "Can not call constructor"); - } - if (EG(This) && Z_OBJCE_P(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { - zend_error(E_COMPILE_ERROR, "Cannot call private %v::__construct()", ce->name); - } - EX(fbc) = ce->constructor; - } - - if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { - EX(object) = NULL; - } else { - if (IS_CV != IS_UNUSED && - EG(This) && - Z_OBJ_HT_P(EG(This))->get_class_entry && - !instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) { - /* We are calling method of the other (incompatible) class, - but passing $this. This is done for compatibility with php-4. */ - zend_error(E_STRICT, "Non-static method %v::%v() should not be called statically, assuming $this from incompatible context", EX(fbc)->common.scope->name, EX(fbc)->common.function_name); - - } - if ((EX(object) = EG(This))) { - EX(object)->refcount++; - } - } - - ZEND_VM_NEXT_OPCODE(); -} - static int ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -1338,10 +1107,38 @@ static int ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) function_name_strval = Z_UNIVAL_P(function_name); function_name_strlen = Z_UNILEN_P(function_name); - lcname = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_UNIVAL_P(function_name), function_name_strlen, 1, &lcname_len); + if (IS_CV != IS_CONST && + ((Z_TYPE_P(function_name) == IS_UNICODE && + Z_USTRVAL_P(function_name)[0] == ':' && + Z_USTRVAL_P(function_name)[1] == ':') || + (Z_TYPE_P(function_name) == IS_STRING && + Z_STRVAL_P(function_name)[0] == ':' && + Z_STRVAL_P(function_name)[1] == ':'))) { + if (Z_TYPE_P(function_name) == IS_UNICODE) { + lcname = zend_u_str_case_fold(IS_UNICODE, (zstr)(Z_USTRVAL_P(function_name)+2), function_name_strlen-2, 1, &lcname_len); + } else { + lcname = zend_u_str_case_fold(IS_STRING, (zstr)(Z_STRVAL_P(function_name)+2), function_name_strlen-2, 1, &lcname_len); + } + } else { + lcname = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_UNIVAL_P(function_name), function_name_strlen, 1, &lcname_len); + } if (zend_u_hash_find(EG(function_table), Z_TYPE_P(function_name), lcname, lcname_len+1, (void **) &function)==FAILURE) { efree(lcname.v); - zend_error_noreturn(E_ERROR, "Call to undefined function %R()", Z_TYPE_P(function_name), function_name_strval); + + if (IS_CV == IS_CONST && opline->op1.op_type == IS_CONST) { + if (Z_TYPE_P(function_name) == IS_UNICODE) { + lcname = zend_u_str_case_fold(IS_UNICODE, (zstr)(Z_USTRVAL_P(function_name)+Z_LVAL(opline->op1.u.constant)), function_name_strlen-Z_LVAL(opline->op1.u.constant), 1, &lcname_len); + } else { + lcname = zend_u_str_case_fold(IS_STRING, (zstr)(Z_STRVAL_P(function_name)+Z_LVAL(opline->op1.u.constant)), function_name_strlen-Z_LVAL(opline->op1.u.constant), 1, &lcname_len); + } + if (zend_u_hash_find(EG(function_table), Z_TYPE_P(function_name), lcname, lcname_len+1, (void **) &function)==FAILURE || + function->type != ZEND_INTERNAL_FUNCTION) { + efree(lcname.v); + zend_error_noreturn(E_ERROR, "Call to undefined function %R()", Z_TYPE_P(function_name), function_name_strval); + } + } else { + zend_error_noreturn(E_ERROR, "Call to undefined function %R()", Z_TYPE_P(function_name), function_name_strval); + } } efree(lcname.v); @@ -2688,7 +2485,108 @@ static int ZEND_FETCH_DIM_TMP_VAR_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_A SELECTIVE_PZVAL_LOCK(*EX_T(opline->result.u.var).var.ptr_ptr, &opline->result); } - AI_USE_PTR(EX_T(opline->result.u.var).var); + AI_USE_PTR(EX_T(opline->result.u.var).var); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + zend_op *opline = EX(opline); + zval *function_name; + zend_class_entry *ce; + + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + + if (IS_CONST == IS_CONST && IS_CONST == IS_CONST) { + /* try a function in namespace */ + zstr fname, lcname; + unsigned int len, lcname_len; + + len = Z_UNILEN(opline->op1.u.constant) + 2 + Z_UNILEN(opline->op2.u.constant); + if (UG(unicode)) { + fname.u = eumalloc(len + 1); + memcpy(fname.u, Z_USTRVAL(opline->op1.u.constant), UBYTES(Z_USTRLEN(opline->op1.u.constant))); + fname.u[Z_USTRLEN(opline->op1.u.constant)] = ':'; + fname.u[Z_USTRLEN(opline->op1.u.constant)+1] = ':'; + memcpy(fname.u+Z_USTRLEN(opline->op1.u.constant)+2, + Z_USTRVAL(opline->op2.u.constant), + UBYTES(Z_USTRLEN(opline->op2.u.constant)+1)); + lcname = zend_u_str_case_fold(IS_UNICODE, fname, len, 1, &lcname_len); + } else { + fname.s = emalloc(len + 1); + memcpy(fname.s, Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant)); + fname.s[Z_STRLEN(opline->op1.u.constant)] = ':'; + fname.s[Z_STRLEN(opline->op1.u.constant)+1] = ':'; + memcpy(fname.s+Z_STRLEN(opline->op1.u.constant)+2, + Z_STRVAL(opline->op2.u.constant), + Z_STRLEN(opline->op2.u.constant)+1); + lcname = zend_u_str_case_fold(IS_STRING, fname, len, 1, &lcname_len); + } + efree(fname.v); + + if (zend_u_hash_find(EG(function_table), ZEND_STR_TYPE, lcname, lcname_len+1, (void **) &EX(fbc))==SUCCESS) { + efree(lcname.v); + EX(object) = NULL; + ZEND_VM_NEXT_OPCODE(); + } + efree(lcname.v); + + /* no function found. try a static method in class */ + ce = zend_u_fetch_class(Z_TYPE(opline->op1.u.constant), Z_UNIVAL(opline->op1.u.constant), Z_UNILEN(opline->op1.u.constant), opline->extended_value TSRMLS_CC); + } else { + ce = EX_T(opline->op1.u.var).class_entry; + } + if(IS_CONST != IS_UNUSED) { + zstr function_name_strval; + unsigned int function_name_strlen; + zend_bool is_const = (IS_CONST == IS_CONST); + + + if (is_const) { + function_name_strval = Z_UNIVAL(opline->op2.u.constant); + function_name_strlen = Z_UNILEN(opline->op2.u.constant); + } else { + function_name = &opline->op2.u.constant; + + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { + zend_error_noreturn(E_ERROR, "Function name must be a string"); + } + function_name_strval = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_UNIVAL_P(function_name), Z_UNILEN_P(function_name), 1, &function_name_strlen); + } + + EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); + + if (!is_const) { + efree(function_name_strval.v); + + } + } else { + if(!ce->constructor) { + zend_error_noreturn(E_ERROR, "Can not call constructor"); + } + if (EG(This) && Z_OBJCE_P(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { + zend_error(E_COMPILE_ERROR, "Cannot call private %v::__construct()", ce->name); + } + EX(fbc) = ce->constructor; + } + + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { + EX(object) = NULL; + } else { + if (IS_CONST != IS_UNUSED && + EG(This) && + Z_OBJ_HT_P(EG(This))->get_class_entry && + !instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) { + /* We are calling method of the other (incompatible) class, + but passing $this. This is done for compatibility with php-4. */ + zend_error(E_STRICT, "Non-static method %v::%v() should not be called statically, assuming $this from incompatible context", EX(fbc)->common.scope->name, EX(fbc)->common.function_name); + + } + if ((EX(object) = EG(This))) { + EX(object)->refcount++; + } + } + ZEND_VM_NEXT_OPCODE(); } @@ -2723,53 +2621,6 @@ static int ZEND_CASE_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) ZEND_VM_NEXT_OPCODE(); } -static int ZEND_FETCH_CONSTANT_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - zend_op *opline = EX(opline); - zend_class_entry *ce = NULL; - zval **value; - - if (IS_CONST == IS_UNUSED) { -/* This seems to be a reminant of namespaces - if (EG(scope)) { - ce = EG(scope); - if (zend_hash_find(&ce->constants_table, Z_STRVAL(opline->op2.u.constant), Z_STRLEN(opline->op2.u.constant)+1, (void **) &value) == SUCCESS) { - zval_update_constant(value, (void *) 1 TSRMLS_CC); - EX_T(opline->result.u.var).tmp_var = **value; - zval_copy_ctor(&EX_T(opline->result.u.var).tmp_var); - ZEND_VM_NEXT_OPCODE(); - } - } -*/ - if (!zend_u_get_constant(Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant), Z_UNILEN(opline->op2.u.constant), &EX_T(opline->result.u.var).tmp_var, NULL TSRMLS_CC)) { - zend_error(E_NOTICE, "Use of undefined constant %R - assumed '%R'", - Z_TYPE(opline->op2.u.constant), - Z_UNIVAL(opline->op2.u.constant), - Z_TYPE(opline->op2.u.constant), - Z_UNIVAL(opline->op2.u.constant)); - EX_T(opline->result.u.var).tmp_var = opline->op2.u.constant; - zval_copy_ctor(&EX_T(opline->result.u.var).tmp_var); - } - ZEND_VM_NEXT_OPCODE(); - } - - ce = EX_T(opline->op1.u.var).class_entry; - - if (zend_u_hash_find(&ce->constants_table, Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant), Z_UNILEN(opline->op2.u.constant)+1, (void **) &value) == SUCCESS) { - zend_class_entry *old_scope = EG(scope); - - EG(scope) = ce; - zval_update_constant(value, (void *) 1 TSRMLS_CC); - EG(scope) = old_scope; - EX_T(opline->result.u.var).tmp_var = **value; - zval_copy_ctor(&EX_T(opline->result.u.var).tmp_var); - } else { - zend_error_noreturn(E_ERROR, "Undefined class constant '%R'", Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant)); - } - - ZEND_VM_NEXT_OPCODE(); -} - static int ZEND_ADD_ARRAY_ELEMENT_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -3098,6 +2949,107 @@ static int ZEND_BOOL_XOR_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) ZEND_VM_NEXT_OPCODE(); } +static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + zend_op *opline = EX(opline); + zval *function_name; + zend_class_entry *ce; + + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + + if (IS_CONST == IS_CONST && IS_TMP_VAR == IS_CONST) { + /* try a function in namespace */ + zstr fname, lcname; + unsigned int len, lcname_len; + + len = Z_UNILEN(opline->op1.u.constant) + 2 + Z_UNILEN(opline->op2.u.constant); + if (UG(unicode)) { + fname.u = eumalloc(len + 1); + memcpy(fname.u, Z_USTRVAL(opline->op1.u.constant), UBYTES(Z_USTRLEN(opline->op1.u.constant))); + fname.u[Z_USTRLEN(opline->op1.u.constant)] = ':'; + fname.u[Z_USTRLEN(opline->op1.u.constant)+1] = ':'; + memcpy(fname.u+Z_USTRLEN(opline->op1.u.constant)+2, + Z_USTRVAL(opline->op2.u.constant), + UBYTES(Z_USTRLEN(opline->op2.u.constant)+1)); + lcname = zend_u_str_case_fold(IS_UNICODE, fname, len, 1, &lcname_len); + } else { + fname.s = emalloc(len + 1); + memcpy(fname.s, Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant)); + fname.s[Z_STRLEN(opline->op1.u.constant)] = ':'; + fname.s[Z_STRLEN(opline->op1.u.constant)+1] = ':'; + memcpy(fname.s+Z_STRLEN(opline->op1.u.constant)+2, + Z_STRVAL(opline->op2.u.constant), + Z_STRLEN(opline->op2.u.constant)+1); + lcname = zend_u_str_case_fold(IS_STRING, fname, len, 1, &lcname_len); + } + efree(fname.v); + + if (zend_u_hash_find(EG(function_table), ZEND_STR_TYPE, lcname, lcname_len+1, (void **) &EX(fbc))==SUCCESS) { + efree(lcname.v); + EX(object) = NULL; + ZEND_VM_NEXT_OPCODE(); + } + efree(lcname.v); + + /* no function found. try a static method in class */ + ce = zend_u_fetch_class(Z_TYPE(opline->op1.u.constant), Z_UNIVAL(opline->op1.u.constant), Z_UNILEN(opline->op1.u.constant), opline->extended_value TSRMLS_CC); + } else { + ce = EX_T(opline->op1.u.var).class_entry; + } + if(IS_TMP_VAR != IS_UNUSED) { + zstr function_name_strval; + unsigned int function_name_strlen; + zend_bool is_const = (IS_TMP_VAR == IS_CONST); + zend_free_op free_op2; + + if (is_const) { + function_name_strval = Z_UNIVAL(opline->op2.u.constant); + function_name_strlen = Z_UNILEN(opline->op2.u.constant); + } else { + function_name = _get_zval_ptr_tmp(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); + + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { + zend_error_noreturn(E_ERROR, "Function name must be a string"); + } + function_name_strval = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_UNIVAL_P(function_name), Z_UNILEN_P(function_name), 1, &function_name_strlen); + } + + EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); + + if (!is_const) { + efree(function_name_strval.v); + zval_dtor(free_op2.var); + } + } else { + if(!ce->constructor) { + zend_error_noreturn(E_ERROR, "Can not call constructor"); + } + if (EG(This) && Z_OBJCE_P(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { + zend_error(E_COMPILE_ERROR, "Cannot call private %v::__construct()", ce->name); + } + EX(fbc) = ce->constructor; + } + + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { + EX(object) = NULL; + } else { + if (IS_TMP_VAR != IS_UNUSED && + EG(This) && + Z_OBJ_HT_P(EG(This))->get_class_entry && + !instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) { + /* We are calling method of the other (incompatible) class, + but passing $this. This is done for compatibility with php-4. */ + zend_error(E_STRICT, "Non-static method %v::%v() should not be called statically, assuming $this from incompatible context", EX(fbc)->common.scope->name, EX(fbc)->common.function_name); + + } + if ((EX(object) = EG(This))) { + EX(object)->refcount++; + } + } + + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_CASE_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -3458,6 +3410,107 @@ static int ZEND_BOOL_XOR_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) ZEND_VM_NEXT_OPCODE(); } +static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + zend_op *opline = EX(opline); + zval *function_name; + zend_class_entry *ce; + + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + + if (IS_CONST == IS_CONST && IS_VAR == IS_CONST) { + /* try a function in namespace */ + zstr fname, lcname; + unsigned int len, lcname_len; + + len = Z_UNILEN(opline->op1.u.constant) + 2 + Z_UNILEN(opline->op2.u.constant); + if (UG(unicode)) { + fname.u = eumalloc(len + 1); + memcpy(fname.u, Z_USTRVAL(opline->op1.u.constant), UBYTES(Z_USTRLEN(opline->op1.u.constant))); + fname.u[Z_USTRLEN(opline->op1.u.constant)] = ':'; + fname.u[Z_USTRLEN(opline->op1.u.constant)+1] = ':'; + memcpy(fname.u+Z_USTRLEN(opline->op1.u.constant)+2, + Z_USTRVAL(opline->op2.u.constant), + UBYTES(Z_USTRLEN(opline->op2.u.constant)+1)); + lcname = zend_u_str_case_fold(IS_UNICODE, fname, len, 1, &lcname_len); + } else { + fname.s = emalloc(len + 1); + memcpy(fname.s, Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant)); + fname.s[Z_STRLEN(opline->op1.u.constant)] = ':'; + fname.s[Z_STRLEN(opline->op1.u.constant)+1] = ':'; + memcpy(fname.s+Z_STRLEN(opline->op1.u.constant)+2, + Z_STRVAL(opline->op2.u.constant), + Z_STRLEN(opline->op2.u.constant)+1); + lcname = zend_u_str_case_fold(IS_STRING, fname, len, 1, &lcname_len); + } + efree(fname.v); + + if (zend_u_hash_find(EG(function_table), ZEND_STR_TYPE, lcname, lcname_len+1, (void **) &EX(fbc))==SUCCESS) { + efree(lcname.v); + EX(object) = NULL; + ZEND_VM_NEXT_OPCODE(); + } + efree(lcname.v); + + /* no function found. try a static method in class */ + ce = zend_u_fetch_class(Z_TYPE(opline->op1.u.constant), Z_UNIVAL(opline->op1.u.constant), Z_UNILEN(opline->op1.u.constant), opline->extended_value TSRMLS_CC); + } else { + ce = EX_T(opline->op1.u.var).class_entry; + } + if(IS_VAR != IS_UNUSED) { + zstr function_name_strval; + unsigned int function_name_strlen; + zend_bool is_const = (IS_VAR == IS_CONST); + zend_free_op free_op2; + + if (is_const) { + function_name_strval = Z_UNIVAL(opline->op2.u.constant); + function_name_strlen = Z_UNILEN(opline->op2.u.constant); + } else { + function_name = _get_zval_ptr_var(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); + + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { + zend_error_noreturn(E_ERROR, "Function name must be a string"); + } + function_name_strval = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_UNIVAL_P(function_name), Z_UNILEN_P(function_name), 1, &function_name_strlen); + } + + EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); + + if (!is_const) { + efree(function_name_strval.v); + if (free_op2.var) {zval_ptr_dtor(&free_op2.var);}; + } + } else { + if(!ce->constructor) { + zend_error_noreturn(E_ERROR, "Can not call constructor"); + } + if (EG(This) && Z_OBJCE_P(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { + zend_error(E_COMPILE_ERROR, "Cannot call private %v::__construct()", ce->name); + } + EX(fbc) = ce->constructor; + } + + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { + EX(object) = NULL; + } else { + if (IS_VAR != IS_UNUSED && + EG(This) && + Z_OBJ_HT_P(EG(This))->get_class_entry && + !instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) { + /* We are calling method of the other (incompatible) class, + but passing $this. This is done for compatibility with php-4. */ + zend_error(E_STRICT, "Non-static method %v::%v() should not be called statically, assuming $this from incompatible context", EX(fbc)->common.scope->name, EX(fbc)->common.function_name); + + } + if ((EX(object) = EG(This))) { + EX(object)->refcount++; + } + } + + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_CASE_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -3584,6 +3637,107 @@ static int ZEND_INIT_ARRAY_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } +static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + zend_op *opline = EX(opline); + zval *function_name; + zend_class_entry *ce; + + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + + if (IS_CONST == IS_CONST && IS_UNUSED == IS_CONST) { + /* try a function in namespace */ + zstr fname, lcname; + unsigned int len, lcname_len; + + len = Z_UNILEN(opline->op1.u.constant) + 2 + Z_UNILEN(opline->op2.u.constant); + if (UG(unicode)) { + fname.u = eumalloc(len + 1); + memcpy(fname.u, Z_USTRVAL(opline->op1.u.constant), UBYTES(Z_USTRLEN(opline->op1.u.constant))); + fname.u[Z_USTRLEN(opline->op1.u.constant)] = ':'; + fname.u[Z_USTRLEN(opline->op1.u.constant)+1] = ':'; + memcpy(fname.u+Z_USTRLEN(opline->op1.u.constant)+2, + Z_USTRVAL(opline->op2.u.constant), + UBYTES(Z_USTRLEN(opline->op2.u.constant)+1)); + lcname = zend_u_str_case_fold(IS_UNICODE, fname, len, 1, &lcname_len); + } else { + fname.s = emalloc(len + 1); + memcpy(fname.s, Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant)); + fname.s[Z_STRLEN(opline->op1.u.constant)] = ':'; + fname.s[Z_STRLEN(opline->op1.u.constant)+1] = ':'; + memcpy(fname.s+Z_STRLEN(opline->op1.u.constant)+2, + Z_STRVAL(opline->op2.u.constant), + Z_STRLEN(opline->op2.u.constant)+1); + lcname = zend_u_str_case_fold(IS_STRING, fname, len, 1, &lcname_len); + } + efree(fname.v); + + if (zend_u_hash_find(EG(function_table), ZEND_STR_TYPE, lcname, lcname_len+1, (void **) &EX(fbc))==SUCCESS) { + efree(lcname.v); + EX(object) = NULL; + ZEND_VM_NEXT_OPCODE(); + } + efree(lcname.v); + + /* no function found. try a static method in class */ + ce = zend_u_fetch_class(Z_TYPE(opline->op1.u.constant), Z_UNIVAL(opline->op1.u.constant), Z_UNILEN(opline->op1.u.constant), opline->extended_value TSRMLS_CC); + } else { + ce = EX_T(opline->op1.u.var).class_entry; + } + if(IS_UNUSED != IS_UNUSED) { + zstr function_name_strval; + unsigned int function_name_strlen; + zend_bool is_const = (IS_UNUSED == IS_CONST); + + + if (is_const) { + function_name_strval = Z_UNIVAL(opline->op2.u.constant); + function_name_strlen = Z_UNILEN(opline->op2.u.constant); + } else { + function_name = NULL; + + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { + zend_error_noreturn(E_ERROR, "Function name must be a string"); + } + function_name_strval = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_UNIVAL_P(function_name), Z_UNILEN_P(function_name), 1, &function_name_strlen); + } + + EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); + + if (!is_const) { + efree(function_name_strval.v); + + } + } else { + if(!ce->constructor) { + zend_error_noreturn(E_ERROR, "Can not call constructor"); + } + if (EG(This) && Z_OBJCE_P(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { + zend_error(E_COMPILE_ERROR, "Cannot call private %v::__construct()", ce->name); + } + EX(fbc) = ce->constructor; + } + + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { + EX(object) = NULL; + } else { + if (IS_UNUSED != IS_UNUSED && + EG(This) && + Z_OBJ_HT_P(EG(This))->get_class_entry && + !instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) { + /* We are calling method of the other (incompatible) class, + but passing $this. This is done for compatibility with php-4. */ + zend_error(E_STRICT, "Non-static method %v::%v() should not be called statically, assuming $this from incompatible context", EX(fbc)->common.scope->name, EX(fbc)->common.function_name); + + } + if ((EX(object) = EG(This))) { + EX(object)->refcount++; + } + } + + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_ADD_ARRAY_ELEMENT_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -3912,6 +4066,107 @@ static int ZEND_BOOL_XOR_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) ZEND_VM_NEXT_OPCODE(); } +static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + zend_op *opline = EX(opline); + zval *function_name; + zend_class_entry *ce; + + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + + if (IS_CONST == IS_CONST && IS_CV == IS_CONST) { + /* try a function in namespace */ + zstr fname, lcname; + unsigned int len, lcname_len; + + len = Z_UNILEN(opline->op1.u.constant) + 2 + Z_UNILEN(opline->op2.u.constant); + if (UG(unicode)) { + fname.u = eumalloc(len + 1); + memcpy(fname.u, Z_USTRVAL(opline->op1.u.constant), UBYTES(Z_USTRLEN(opline->op1.u.constant))); + fname.u[Z_USTRLEN(opline->op1.u.constant)] = ':'; + fname.u[Z_USTRLEN(opline->op1.u.constant)+1] = ':'; + memcpy(fname.u+Z_USTRLEN(opline->op1.u.constant)+2, + Z_USTRVAL(opline->op2.u.constant), + UBYTES(Z_USTRLEN(opline->op2.u.constant)+1)); + lcname = zend_u_str_case_fold(IS_UNICODE, fname, len, 1, &lcname_len); + } else { + fname.s = emalloc(len + 1); + memcpy(fname.s, Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant)); + fname.s[Z_STRLEN(opline->op1.u.constant)] = ':'; + fname.s[Z_STRLEN(opline->op1.u.constant)+1] = ':'; + memcpy(fname.s+Z_STRLEN(opline->op1.u.constant)+2, + Z_STRVAL(opline->op2.u.constant), + Z_STRLEN(opline->op2.u.constant)+1); + lcname = zend_u_str_case_fold(IS_STRING, fname, len, 1, &lcname_len); + } + efree(fname.v); + + if (zend_u_hash_find(EG(function_table), ZEND_STR_TYPE, lcname, lcname_len+1, (void **) &EX(fbc))==SUCCESS) { + efree(lcname.v); + EX(object) = NULL; + ZEND_VM_NEXT_OPCODE(); + } + efree(lcname.v); + + /* no function found. try a static method in class */ + ce = zend_u_fetch_class(Z_TYPE(opline->op1.u.constant), Z_UNIVAL(opline->op1.u.constant), Z_UNILEN(opline->op1.u.constant), opline->extended_value TSRMLS_CC); + } else { + ce = EX_T(opline->op1.u.var).class_entry; + } + if(IS_CV != IS_UNUSED) { + zstr function_name_strval; + unsigned int function_name_strlen; + zend_bool is_const = (IS_CV == IS_CONST); + + + if (is_const) { + function_name_strval = Z_UNIVAL(opline->op2.u.constant); + function_name_strlen = Z_UNILEN(opline->op2.u.constant); + } else { + function_name = _get_zval_ptr_cv(&opline->op2, EX(Ts), BP_VAR_R TSRMLS_CC); + + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { + zend_error_noreturn(E_ERROR, "Function name must be a string"); + } + function_name_strval = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_UNIVAL_P(function_name), Z_UNILEN_P(function_name), 1, &function_name_strlen); + } + + EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); + + if (!is_const) { + efree(function_name_strval.v); + + } + } else { + if(!ce->constructor) { + zend_error_noreturn(E_ERROR, "Can not call constructor"); + } + if (EG(This) && Z_OBJCE_P(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { + zend_error(E_COMPILE_ERROR, "Cannot call private %v::__construct()", ce->name); + } + EX(fbc) = ce->constructor; + } + + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { + EX(object) = NULL; + } else { + if (IS_CV != IS_UNUSED && + EG(This) && + Z_OBJ_HT_P(EG(This))->get_class_entry && + !instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) { + /* We are calling method of the other (incompatible) class, + but passing $this. This is done for compatibility with php-4. */ + zend_error(E_STRICT, "Non-static method %v::%v() should not be called statically, assuming $this from incompatible context", EX(fbc)->common.scope->name, EX(fbc)->common.function_name); + + } + if ((EX(object) = EG(This))) { + EX(object)->refcount++; + } + } + + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_CASE_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -9676,6 +9931,107 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS ZEND_VM_NEXT_OPCODE(); } +static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + zend_op *opline = EX(opline); + zval *function_name; + zend_class_entry *ce; + + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + + if (IS_VAR == IS_CONST && IS_CONST == IS_CONST) { + /* try a function in namespace */ + zstr fname, lcname; + unsigned int len, lcname_len; + + len = Z_UNILEN(opline->op1.u.constant) + 2 + Z_UNILEN(opline->op2.u.constant); + if (UG(unicode)) { + fname.u = eumalloc(len + 1); + memcpy(fname.u, Z_USTRVAL(opline->op1.u.constant), UBYTES(Z_USTRLEN(opline->op1.u.constant))); + fname.u[Z_USTRLEN(opline->op1.u.constant)] = ':'; + fname.u[Z_USTRLEN(opline->op1.u.constant)+1] = ':'; + memcpy(fname.u+Z_USTRLEN(opline->op1.u.constant)+2, + Z_USTRVAL(opline->op2.u.constant), + UBYTES(Z_USTRLEN(opline->op2.u.constant)+1)); + lcname = zend_u_str_case_fold(IS_UNICODE, fname, len, 1, &lcname_len); + } else { + fname.s = emalloc(len + 1); + memcpy(fname.s, Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant)); + fname.s[Z_STRLEN(opline->op1.u.constant)] = ':'; + fname.s[Z_STRLEN(opline->op1.u.constant)+1] = ':'; + memcpy(fname.s+Z_STRLEN(opline->op1.u.constant)+2, + Z_STRVAL(opline->op2.u.constant), + Z_STRLEN(opline->op2.u.constant)+1); + lcname = zend_u_str_case_fold(IS_STRING, fname, len, 1, &lcname_len); + } + efree(fname.v); + + if (zend_u_hash_find(EG(function_table), ZEND_STR_TYPE, lcname, lcname_len+1, (void **) &EX(fbc))==SUCCESS) { + efree(lcname.v); + EX(object) = NULL; + ZEND_VM_NEXT_OPCODE(); + } + efree(lcname.v); + + /* no function found. try a static method in class */ + ce = zend_u_fetch_class(Z_TYPE(opline->op1.u.constant), Z_UNIVAL(opline->op1.u.constant), Z_UNILEN(opline->op1.u.constant), opline->extended_value TSRMLS_CC); + } else { + ce = EX_T(opline->op1.u.var).class_entry; + } + if(IS_CONST != IS_UNUSED) { + zstr function_name_strval; + unsigned int function_name_strlen; + zend_bool is_const = (IS_CONST == IS_CONST); + + + if (is_const) { + function_name_strval = Z_UNIVAL(opline->op2.u.constant); + function_name_strlen = Z_UNILEN(opline->op2.u.constant); + } else { + function_name = &opline->op2.u.constant; + + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { + zend_error_noreturn(E_ERROR, "Function name must be a string"); + } + function_name_strval = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_UNIVAL_P(function_name), Z_UNILEN_P(function_name), 1, &function_name_strlen); + } + + EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); + + if (!is_const) { + efree(function_name_strval.v); + + } + } else { + if(!ce->constructor) { + zend_error_noreturn(E_ERROR, "Can not call constructor"); + } + if (EG(This) && Z_OBJCE_P(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { + zend_error(E_COMPILE_ERROR, "Cannot call private %v::__construct()", ce->name); + } + EX(fbc) = ce->constructor; + } + + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { + EX(object) = NULL; + } else { + if (IS_CONST != IS_UNUSED && + EG(This) && + Z_OBJ_HT_P(EG(This))->get_class_entry && + !instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) { + /* We are calling method of the other (incompatible) class, + but passing $this. This is done for compatibility with php-4. */ + zend_error(E_STRICT, "Non-static method %v::%v() should not be called statically, assuming $this from incompatible context", EX(fbc)->common.scope->name, EX(fbc)->common.function_name); + + } + if ((EX(object) = EG(This))) { + EX(object)->refcount++; + } + } + + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_CASE_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -9707,6 +10063,53 @@ static int ZEND_CASE_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FETCH_CONSTANT_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + zend_op *opline = EX(opline); + zend_class_entry *ce = NULL; + zval **value; + + if (IS_VAR == IS_UNUSED) { +/* This seems to be a reminant of namespaces + if (EG(scope)) { + ce = EG(scope); + if (zend_hash_find(&ce->constants_table, Z_STRVAL(opline->op2.u.constant), Z_STRLEN(opline->op2.u.constant)+1, (void **) &value) == SUCCESS) { + zval_update_constant(value, (void *) 1 TSRMLS_CC); + EX_T(opline->result.u.var).tmp_var = **value; + zval_copy_ctor(&EX_T(opline->result.u.var).tmp_var); + ZEND_VM_NEXT_OPCODE(); + } + } +*/ + if (!zend_u_get_constant(Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant), Z_UNILEN(opline->op2.u.constant), &EX_T(opline->result.u.var).tmp_var, NULL TSRMLS_CC)) { + zend_error(E_NOTICE, "Use of undefined constant %R - assumed '%R'", + Z_TYPE(opline->op2.u.constant), + Z_UNIVAL(opline->op2.u.constant), + Z_TYPE(opline->op2.u.constant), + Z_UNIVAL(opline->op2.u.constant)); + EX_T(opline->result.u.var).tmp_var = opline->op2.u.constant; + zval_copy_ctor(&EX_T(opline->result.u.var).tmp_var); + } + ZEND_VM_NEXT_OPCODE(); + } + + ce = EX_T(opline->op1.u.var).class_entry; + + if (zend_u_hash_find(&ce->constants_table, Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant), Z_UNILEN(opline->op2.u.constant)+1, (void **) &value) == SUCCESS) { + zend_class_entry *old_scope = EG(scope); + + EG(scope) = ce; + zval_update_constant(value, (void *) 1 TSRMLS_CC); + EG(scope) = old_scope; + EX_T(opline->result.u.var).tmp_var = **value; + zval_copy_ctor(&EX_T(opline->result.u.var).tmp_var); + } else { + zend_error_noreturn(E_ERROR, "Undefined class constant '%R'", Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant)); + } + + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_ADD_ARRAY_ELEMENT_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -11191,32 +11594,133 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_error_noreturn(E_ERROR, "Object does not support method calls"); } - /* First, locate the function. */ - EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); - if (!EX(fbc)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %R::%R()", type, Z_OBJ_CLASS_NAME_P(EX(object)), Z_TYPE_P(function_name), function_name_strval); + /* First, locate the function. */ + EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); + if (!EX(fbc)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %R::%R()", type, Z_OBJ_CLASS_NAME_P(EX(object)), Z_TYPE_P(function_name), function_name_strval); + } + } else { + zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); + } + + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { + EX(object) = NULL; + } else { + if (!PZVAL_IS_REF(EX(object))) { + EX(object)->refcount++; /* For $this pointer */ + } else { + zval *this_ptr; + ALLOC_ZVAL(this_ptr); + INIT_PZVAL_COPY(this_ptr, EX(object)); + zval_copy_ctor(this_ptr); + EX(object) = this_ptr; + } + } + + zval_dtor(free_op2.var); + if (free_op1.var) {zval_ptr_dtor(&free_op1.var);}; + + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + zend_op *opline = EX(opline); + zval *function_name; + zend_class_entry *ce; + + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + + if (IS_VAR == IS_CONST && IS_TMP_VAR == IS_CONST) { + /* try a function in namespace */ + zstr fname, lcname; + unsigned int len, lcname_len; + + len = Z_UNILEN(opline->op1.u.constant) + 2 + Z_UNILEN(opline->op2.u.constant); + if (UG(unicode)) { + fname.u = eumalloc(len + 1); + memcpy(fname.u, Z_USTRVAL(opline->op1.u.constant), UBYTES(Z_USTRLEN(opline->op1.u.constant))); + fname.u[Z_USTRLEN(opline->op1.u.constant)] = ':'; + fname.u[Z_USTRLEN(opline->op1.u.constant)+1] = ':'; + memcpy(fname.u+Z_USTRLEN(opline->op1.u.constant)+2, + Z_USTRVAL(opline->op2.u.constant), + UBYTES(Z_USTRLEN(opline->op2.u.constant)+1)); + lcname = zend_u_str_case_fold(IS_UNICODE, fname, len, 1, &lcname_len); + } else { + fname.s = emalloc(len + 1); + memcpy(fname.s, Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant)); + fname.s[Z_STRLEN(opline->op1.u.constant)] = ':'; + fname.s[Z_STRLEN(opline->op1.u.constant)+1] = ':'; + memcpy(fname.s+Z_STRLEN(opline->op1.u.constant)+2, + Z_STRVAL(opline->op2.u.constant), + Z_STRLEN(opline->op2.u.constant)+1); + lcname = zend_u_str_case_fold(IS_STRING, fname, len, 1, &lcname_len); + } + efree(fname.v); + + if (zend_u_hash_find(EG(function_table), ZEND_STR_TYPE, lcname, lcname_len+1, (void **) &EX(fbc))==SUCCESS) { + efree(lcname.v); + EX(object) = NULL; + ZEND_VM_NEXT_OPCODE(); + } + efree(lcname.v); + + /* no function found. try a static method in class */ + ce = zend_u_fetch_class(Z_TYPE(opline->op1.u.constant), Z_UNIVAL(opline->op1.u.constant), Z_UNILEN(opline->op1.u.constant), opline->extended_value TSRMLS_CC); + } else { + ce = EX_T(opline->op1.u.var).class_entry; + } + if(IS_TMP_VAR != IS_UNUSED) { + zstr function_name_strval; + unsigned int function_name_strlen; + zend_bool is_const = (IS_TMP_VAR == IS_CONST); + zend_free_op free_op2; + + if (is_const) { + function_name_strval = Z_UNIVAL(opline->op2.u.constant); + function_name_strlen = Z_UNILEN(opline->op2.u.constant); + } else { + function_name = _get_zval_ptr_tmp(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); + + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { + zend_error_noreturn(E_ERROR, "Function name must be a string"); + } + function_name_strval = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_UNIVAL_P(function_name), Z_UNILEN_P(function_name), 1, &function_name_strlen); + } + + EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); + + if (!is_const) { + efree(function_name_strval.v); + zval_dtor(free_op2.var); } } else { - zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); + if(!ce->constructor) { + zend_error_noreturn(E_ERROR, "Can not call constructor"); + } + if (EG(This) && Z_OBJCE_P(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { + zend_error(E_COMPILE_ERROR, "Cannot call private %v::__construct()", ce->name); + } + EX(fbc) = ce->constructor; } if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { EX(object) = NULL; } else { - if (!PZVAL_IS_REF(EX(object))) { - EX(object)->refcount++; /* For $this pointer */ - } else { - zval *this_ptr; - ALLOC_ZVAL(this_ptr); - INIT_PZVAL_COPY(this_ptr, EX(object)); - zval_copy_ctor(this_ptr); - EX(object) = this_ptr; + if (IS_TMP_VAR != IS_UNUSED && + EG(This) && + Z_OBJ_HT_P(EG(This))->get_class_entry && + !instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) { + /* We are calling method of the other (incompatible) class, + but passing $this. This is done for compatibility with php-4. */ + zend_error(E_STRICT, "Non-static method %v::%v() should not be called statically, assuming $this from incompatible context", EX(fbc)->common.scope->name, EX(fbc)->common.function_name); + + } + if ((EX(object) = EG(This))) { + EX(object)->refcount++; } } - zval_dtor(free_op2.var); - if (free_op1.var) {zval_ptr_dtor(&free_op1.var);}; - ZEND_VM_NEXT_OPCODE(); } @@ -12803,6 +13307,107 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) ZEND_VM_NEXT_OPCODE(); } +static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + zend_op *opline = EX(opline); + zval *function_name; + zend_class_entry *ce; + + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + + if (IS_VAR == IS_CONST && IS_VAR == IS_CONST) { + /* try a function in namespace */ + zstr fname, lcname; + unsigned int len, lcname_len; + + len = Z_UNILEN(opline->op1.u.constant) + 2 + Z_UNILEN(opline->op2.u.constant); + if (UG(unicode)) { + fname.u = eumalloc(len + 1); + memcpy(fname.u, Z_USTRVAL(opline->op1.u.constant), UBYTES(Z_USTRLEN(opline->op1.u.constant))); + fname.u[Z_USTRLEN(opline->op1.u.constant)] = ':'; + fname.u[Z_USTRLEN(opline->op1.u.constant)+1] = ':'; + memcpy(fname.u+Z_USTRLEN(opline->op1.u.constant)+2, + Z_USTRVAL(opline->op2.u.constant), + UBYTES(Z_USTRLEN(opline->op2.u.constant)+1)); + lcname = zend_u_str_case_fold(IS_UNICODE, fname, len, 1, &lcname_len); + } else { + fname.s = emalloc(len + 1); + memcpy(fname.s, Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant)); + fname.s[Z_STRLEN(opline->op1.u.constant)] = ':'; + fname.s[Z_STRLEN(opline->op1.u.constant)+1] = ':'; + memcpy(fname.s+Z_STRLEN(opline->op1.u.constant)+2, + Z_STRVAL(opline->op2.u.constant), + Z_STRLEN(opline->op2.u.constant)+1); + lcname = zend_u_str_case_fold(IS_STRING, fname, len, 1, &lcname_len); + } + efree(fname.v); + + if (zend_u_hash_find(EG(function_table), ZEND_STR_TYPE, lcname, lcname_len+1, (void **) &EX(fbc))==SUCCESS) { + efree(lcname.v); + EX(object) = NULL; + ZEND_VM_NEXT_OPCODE(); + } + efree(lcname.v); + + /* no function found. try a static method in class */ + ce = zend_u_fetch_class(Z_TYPE(opline->op1.u.constant), Z_UNIVAL(opline->op1.u.constant), Z_UNILEN(opline->op1.u.constant), opline->extended_value TSRMLS_CC); + } else { + ce = EX_T(opline->op1.u.var).class_entry; + } + if(IS_VAR != IS_UNUSED) { + zstr function_name_strval; + unsigned int function_name_strlen; + zend_bool is_const = (IS_VAR == IS_CONST); + zend_free_op free_op2; + + if (is_const) { + function_name_strval = Z_UNIVAL(opline->op2.u.constant); + function_name_strlen = Z_UNILEN(opline->op2.u.constant); + } else { + function_name = _get_zval_ptr_var(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); + + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { + zend_error_noreturn(E_ERROR, "Function name must be a string"); + } + function_name_strval = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_UNIVAL_P(function_name), Z_UNILEN_P(function_name), 1, &function_name_strlen); + } + + EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); + + if (!is_const) { + efree(function_name_strval.v); + if (free_op2.var) {zval_ptr_dtor(&free_op2.var);}; + } + } else { + if(!ce->constructor) { + zend_error_noreturn(E_ERROR, "Can not call constructor"); + } + if (EG(This) && Z_OBJCE_P(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { + zend_error(E_COMPILE_ERROR, "Cannot call private %v::__construct()", ce->name); + } + EX(fbc) = ce->constructor; + } + + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { + EX(object) = NULL; + } else { + if (IS_VAR != IS_UNUSED && + EG(This) && + Z_OBJ_HT_P(EG(This))->get_class_entry && + !instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) { + /* We are calling method of the other (incompatible) class, + but passing $this. This is done for compatibility with php-4. */ + zend_error(E_STRICT, "Non-static method %v::%v() should not be called statically, assuming $this from incompatible context", EX(fbc)->common.scope->name, EX(fbc)->common.function_name); + + } + if ((EX(object) = EG(This))) { + EX(object)->refcount++; + } + } + + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_CASE_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -13584,6 +14189,107 @@ static int ZEND_ASSIGN_DIM_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) ZEND_VM_NEXT_OPCODE(); } +static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + zend_op *opline = EX(opline); + zval *function_name; + zend_class_entry *ce; + + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + + if (IS_VAR == IS_CONST && IS_UNUSED == IS_CONST) { + /* try a function in namespace */ + zstr fname, lcname; + unsigned int len, lcname_len; + + len = Z_UNILEN(opline->op1.u.constant) + 2 + Z_UNILEN(opline->op2.u.constant); + if (UG(unicode)) { + fname.u = eumalloc(len + 1); + memcpy(fname.u, Z_USTRVAL(opline->op1.u.constant), UBYTES(Z_USTRLEN(opline->op1.u.constant))); + fname.u[Z_USTRLEN(opline->op1.u.constant)] = ':'; + fname.u[Z_USTRLEN(opline->op1.u.constant)+1] = ':'; + memcpy(fname.u+Z_USTRLEN(opline->op1.u.constant)+2, + Z_USTRVAL(opline->op2.u.constant), + UBYTES(Z_USTRLEN(opline->op2.u.constant)+1)); + lcname = zend_u_str_case_fold(IS_UNICODE, fname, len, 1, &lcname_len); + } else { + fname.s = emalloc(len + 1); + memcpy(fname.s, Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant)); + fname.s[Z_STRLEN(opline->op1.u.constant)] = ':'; + fname.s[Z_STRLEN(opline->op1.u.constant)+1] = ':'; + memcpy(fname.s+Z_STRLEN(opline->op1.u.constant)+2, + Z_STRVAL(opline->op2.u.constant), + Z_STRLEN(opline->op2.u.constant)+1); + lcname = zend_u_str_case_fold(IS_STRING, fname, len, 1, &lcname_len); + } + efree(fname.v); + + if (zend_u_hash_find(EG(function_table), ZEND_STR_TYPE, lcname, lcname_len+1, (void **) &EX(fbc))==SUCCESS) { + efree(lcname.v); + EX(object) = NULL; + ZEND_VM_NEXT_OPCODE(); + } + efree(lcname.v); + + /* no function found. try a static method in class */ + ce = zend_u_fetch_class(Z_TYPE(opline->op1.u.constant), Z_UNIVAL(opline->op1.u.constant), Z_UNILEN(opline->op1.u.constant), opline->extended_value TSRMLS_CC); + } else { + ce = EX_T(opline->op1.u.var).class_entry; + } + if(IS_UNUSED != IS_UNUSED) { + zstr function_name_strval; + unsigned int function_name_strlen; + zend_bool is_const = (IS_UNUSED == IS_CONST); + + + if (is_const) { + function_name_strval = Z_UNIVAL(opline->op2.u.constant); + function_name_strlen = Z_UNILEN(opline->op2.u.constant); + } else { + function_name = NULL; + + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { + zend_error_noreturn(E_ERROR, "Function name must be a string"); + } + function_name_strval = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_UNIVAL_P(function_name), Z_UNILEN_P(function_name), 1, &function_name_strlen); + } + + EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); + + if (!is_const) { + efree(function_name_strval.v); + + } + } else { + if(!ce->constructor) { + zend_error_noreturn(E_ERROR, "Can not call constructor"); + } + if (EG(This) && Z_OBJCE_P(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { + zend_error(E_COMPILE_ERROR, "Cannot call private %v::__construct()", ce->name); + } + EX(fbc) = ce->constructor; + } + + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { + EX(object) = NULL; + } else { + if (IS_UNUSED != IS_UNUSED && + EG(This) && + Z_OBJ_HT_P(EG(This))->get_class_entry && + !instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) { + /* We are calling method of the other (incompatible) class, + but passing $this. This is done for compatibility with php-4. */ + zend_error(E_STRICT, "Non-static method %v::%v() should not be called statically, assuming $this from incompatible context", EX(fbc)->common.scope->name, EX(fbc)->common.function_name); + + } + if ((EX(object) = EG(This))) { + EX(object)->refcount++; + } + } + + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_ADD_ARRAY_ELEMENT_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -14817,6 +15523,107 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) ZEND_VM_NEXT_OPCODE(); } +static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + zend_op *opline = EX(opline); + zval *function_name; + zend_class_entry *ce; + + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + + if (IS_VAR == IS_CONST && IS_CV == IS_CONST) { + /* try a function in namespace */ + zstr fname, lcname; + unsigned int len, lcname_len; + + len = Z_UNILEN(opline->op1.u.constant) + 2 + Z_UNILEN(opline->op2.u.constant); + if (UG(unicode)) { + fname.u = eumalloc(len + 1); + memcpy(fname.u, Z_USTRVAL(opline->op1.u.constant), UBYTES(Z_USTRLEN(opline->op1.u.constant))); + fname.u[Z_USTRLEN(opline->op1.u.constant)] = ':'; + fname.u[Z_USTRLEN(opline->op1.u.constant)+1] = ':'; + memcpy(fname.u+Z_USTRLEN(opline->op1.u.constant)+2, + Z_USTRVAL(opline->op2.u.constant), + UBYTES(Z_USTRLEN(opline->op2.u.constant)+1)); + lcname = zend_u_str_case_fold(IS_UNICODE, fname, len, 1, &lcname_len); + } else { + fname.s = emalloc(len + 1); + memcpy(fname.s, Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant)); + fname.s[Z_STRLEN(opline->op1.u.constant)] = ':'; + fname.s[Z_STRLEN(opline->op1.u.constant)+1] = ':'; + memcpy(fname.s+Z_STRLEN(opline->op1.u.constant)+2, + Z_STRVAL(opline->op2.u.constant), + Z_STRLEN(opline->op2.u.constant)+1); + lcname = zend_u_str_case_fold(IS_STRING, fname, len, 1, &lcname_len); + } + efree(fname.v); + + if (zend_u_hash_find(EG(function_table), ZEND_STR_TYPE, lcname, lcname_len+1, (void **) &EX(fbc))==SUCCESS) { + efree(lcname.v); + EX(object) = NULL; + ZEND_VM_NEXT_OPCODE(); + } + efree(lcname.v); + + /* no function found. try a static method in class */ + ce = zend_u_fetch_class(Z_TYPE(opline->op1.u.constant), Z_UNIVAL(opline->op1.u.constant), Z_UNILEN(opline->op1.u.constant), opline->extended_value TSRMLS_CC); + } else { + ce = EX_T(opline->op1.u.var).class_entry; + } + if(IS_CV != IS_UNUSED) { + zstr function_name_strval; + unsigned int function_name_strlen; + zend_bool is_const = (IS_CV == IS_CONST); + + + if (is_const) { + function_name_strval = Z_UNIVAL(opline->op2.u.constant); + function_name_strlen = Z_UNILEN(opline->op2.u.constant); + } else { + function_name = _get_zval_ptr_cv(&opline->op2, EX(Ts), BP_VAR_R TSRMLS_CC); + + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { + zend_error_noreturn(E_ERROR, "Function name must be a string"); + } + function_name_strval = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_UNIVAL_P(function_name), Z_UNILEN_P(function_name), 1, &function_name_strlen); + } + + EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); + + if (!is_const) { + efree(function_name_strval.v); + + } + } else { + if(!ce->constructor) { + zend_error_noreturn(E_ERROR, "Can not call constructor"); + } + if (EG(This) && Z_OBJCE_P(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { + zend_error(E_COMPILE_ERROR, "Cannot call private %v::__construct()", ce->name); + } + EX(fbc) = ce->constructor; + } + + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { + EX(object) = NULL; + } else { + if (IS_CV != IS_UNUSED && + EG(This) && + Z_OBJ_HT_P(EG(This))->get_class_entry && + !instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) { + /* We are calling method of the other (incompatible) class, + but passing $this. This is done for compatibility with php-4. */ + zend_error(E_STRICT, "Non-static method %v::%v() should not be called statically, assuming $this from incompatible context", EX(fbc)->common.scope->name, EX(fbc)->common.function_name); + + } + if ((EX(object) = EG(This))) { + EX(object)->refcount++; + } + } + + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_CASE_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -30195,7 +31002,6 @@ void zend_init_opcodes_handlers() ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, - ZEND_FETCH_CONSTANT_SPEC_CONST_CONST_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, @@ -30206,6 +31012,7 @@ void zend_init_opcodes_handlers() ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, + ZEND_FETCH_CONSTANT_SPEC_VAR_CONST_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, @@ -30545,31 +31352,31 @@ void zend_init_opcodes_handlers() ZEND_INIT_METHOD_CALL_SPEC_CV_VAR_HANDLER, ZEND_NULL_HANDLER, ZEND_INIT_METHOD_CALL_SPEC_CV_CV_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_TMP_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_UNUSED_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_CV_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_TMP_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_UNUSED_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_CV_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_TMP_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_UNUSED_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_CV_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_TMP_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_UNUSED_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_CV_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_TMP_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_UNUSED_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_CV_HANDLER, + ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CONST_HANDLER, + ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_TMP_HANDLER, + ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_VAR_HANDLER, + ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_UNUSED_HANDLER, + ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CV_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CONST_HANDLER, + ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_TMP_HANDLER, + ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_VAR_HANDLER, + ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_UNUSED_HANDLER, + ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CV_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, ZEND_ISSET_ISEMPTY_VAR_SPEC_CONST_HANDLER, ZEND_ISSET_ISEMPTY_VAR_SPEC_CONST_HANDLER, ZEND_ISSET_ISEMPTY_VAR_SPEC_CONST_HANDLER,