fci->size = 0;
fcc->initialized = 0;
break;
- }
+ }
if (zend_fcall_info_init(*arg, fci, fcc, NULL TSRMLS_CC) == SUCCESS) {
break;
break;
}
}
-
+
if (T_arg_type == -1) {
T_arg_type = ZEND_STR_TYPE;
}
get_active_function_name(TSRMLS_C), __num_args); \
return FAILURE; \
}\
-}
+}
ZEND_API int zend_parse_parameters_ex(int flags, int num_args TSRMLS_DC, char *type_spec, ...) /* {{{ */
{
if (UG(unicode)) {
zend_arg_info *args;
int n = ptr->num_args;
-
+
args = internal_function->arg_info = malloc((n + 1) * sizeof(zend_arg_info));
memcpy(args, ptr->arg_info+1, (n + 1) * sizeof(zend_arg_info));
while (n > 0) {
*/
unsigned int lc_func_name_len;
zstr lc_func_name = zend_u_str_case_fold(ZEND_STR_TYPE, internal_function->function_name, fname_len, 0, &lc_func_name_len);
-
+
if ((lc_func_name_len == lc_class_name_len) && !memcmp(lc_func_name.v, lc_class_name.v, UG(unicode)?UBYTES(lc_class_name_len):lc_class_name_len) && !ctor) {
ctor = reg_function;
} else if ((fname_len == sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME))) {
module->module_shutdown_func(module->type, module->module_number TSRMLS_CC);
}
-
+
/* Deinitilaise module globals */
if (module->globals_size) {
#ifdef ZTS
interface_entry = va_arg(interface_list, zend_class_entry *);
zend_do_implement_interface(class_entry, interface_entry TSRMLS_CC);
}
-
+
va_end(interface_list);
}
/* }}} */
*fptr_ptr = NULL;
if (!ce_org) {
+ /* Skip leading :: */
if (Z_TYPE_P(callable) == IS_UNICODE &&
Z_USTRVAL_P(callable)[0] == ':' &&
Z_USTRVAL_P(callable)[1] == ':') {
} else {
lmname = zend_u_str_case_fold(Z_TYPE_P(callable), Z_UNIVAL_P(callable), Z_UNILEN_P(callable), 1, &mlen);
}
+ /* Check if function with given name exists.
+ This may be a compound name that includes namespace name */
if (zend_u_hash_find(EG(function_table), Z_TYPE_P(callable), lmname, mlen+1, (void**)&fptr) == SUCCESS) {
*fptr_ptr = fptr;
efree(lmname.v);
}
efree(lmname.v);
}
+ /* Split name into class/namespace and method/function names */
if (Z_TYPE_P(callable) == IS_UNICODE) {
if ((colon.u = u_strrstr(Z_USTRVAL_P(callable), u_doublecolon)) != NULL) {
mlen = u_strlen(colon.u+2);
}
}
if (colon.v != NULL) {
+ /* This is a compound name.
+ Try to fetch class and then find static method. */
*ce_ptr = zend_u_fetch_class(Z_TYPE_P(callable), Z_UNIVAL_P(callable), clen, ZEND_FETCH_CLASS_AUTO TSRMLS_CC);
if (!*ce_ptr) {
return 0;
return 0;
}
lmname = zend_u_str_case_fold(Z_TYPE_P(callable), mname, mlen, 1, &mlen);
- } else {
+ } else if (ce_org) {
+ /* Try to fetch find static method of given class. */
lmname = zend_u_str_case_fold(Z_TYPE_P(callable), Z_UNIVAL_P(callable), Z_UNILEN_P(callable), 1, &mlen);
- if (ce_org) {
- ftable = &ce_org->function_table;
- *ce_ptr = ce_org;
- } else {
- ftable = EG(function_table);
- }
+ ftable = &ce_org->function_table;
+ *ce_ptr = ce_org;
+ } else {
+ /* We already checked for plain function before. */
+ return 0;
}
retval = zend_u_hash_find(ftable, Z_TYPE_P(callable), lmname, mlen+1, (void**)&fptr) == SUCCESS ? 1 : 0;
fci->symbol_table = NULL;
if (ZEND_U_CASE_EQUAL(ZEND_STR_TYPE, func->common.function_name, USTR_LEN(func->common.function_name), ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME)-1) ||
- ZEND_U_CASE_EQUAL(ZEND_STR_TYPE, func->common.function_name, USTR_LEN(func->common.function_name), ZEND_CALLSTATIC_FUNC_NAME, sizeof(ZEND_CALLSTATIC_FUNC_NAME)-1)) {
+ ZEND_U_CASE_EQUAL(ZEND_STR_TYPE, func->common.function_name, USTR_LEN(func->common.function_name), ZEND_CALLSTATIC_FUNC_NAME, sizeof(ZEND_CALLSTATIC_FUNC_NAME)-1)) {
fcc->initialized = 0;
fcc->function_handler = NULL;
fcc->calling_scope = NULL;
ZEND_API int zend_fcall_info_argp(zend_fcall_info *fci TSRMLS_DC, int argc, zval ***argv) /* {{{ */
{
int i;
-
+
if (argc < 0) {
return FAILURE;
}
-
+
zend_fcall_info_args_clear(fci, !argc);
-
+
if (argc) {
fci->param_count = argc;
fci->params = (zval ***) erealloc(fci->params, fci->param_count * sizeof(zval **));
fci->params[i] = argv[i];
}
}
-
+
return SUCCESS;
}
/* }}} */
{
int i;
zval **arg;
-
+
if (argc < 0) {
return FAILURE;
}
-
+
zend_fcall_info_args_clear(fci, !argc);
-
+
if (argc) {
fci->param_count = argc;
fci->params = (zval ***) erealloc(fci->params, fci->param_count * sizeof(zval **));
-
+
for (i = 0; i < argc; ++i) {
arg = va_arg(*argv, zval **);
ZVAL_ADDREF(*arg);
fci->params[i] = arg;
}
}
-
+
return SUCCESS;
}
/* }}} */
{
int ret;
va_list argv;
-
+
va_start(argv, argc);
ret = zend_fcall_info_argv(fci TSRMLS_CC, argc, &argv);
va_end(argv);
-
+
return ret;
}
/* }}} */
zend_fcall_info_args(fci, args TSRMLS_CC);
}
result = zend_call_function(fci, fcc TSRMLS_CC);
-
+
if (!retval_ptr_ptr && retval) {
zval_ptr_dtor(&retval);
}
{
zval *constant;
- if (ce->type & ZEND_INTERNAL_CLASS) {
+ if (ce->type & ZEND_INTERNAL_CLASS) {
constant = malloc(sizeof(zval));
if (UG(unicode)) {
Z_TYPE_P(constant) = IS_UNICODE;
zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
if (CG(current_namespace)) {
+ /* Prefix function name with current namespcae name */
znode tmp;
tmp.u.constant = *CG(current_namespace);
zend_function *function;
unsigned int lcname_len;
zstr lcname;
+ int prefix_len = 0;
if (check_namespace && CG(current_namespace)) {
+ /* We assume we call function from the current namespace
+ if it is not prefixed. */
znode tmp;
tmp.op_type = IS_CONST;
zval_copy_ctor(&tmp.u.constant);
zend_do_build_namespace_name(&tmp, &tmp, function_name TSRMLS_CC);
*function_name = tmp;
+
+ /* In run-time PHP will check for function with full name and
+ internal function with short name */
+ prefix_len = Z_UNILEN_P(CG(current_namespace)) + 2;
}
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);
+ zend_do_begin_dynamic_function_call(function_name, prefix_len TSRMLS_CC);
efree(lcname.v);
return 1; /* Dynamic */
}
}
/* }}} */
-void zend_do_begin_dynamic_function_call(znode *function_name TSRMLS_DC) /* {{{ */
+void zend_do_begin_dynamic_function_call(znode *function_name, int prefix_len TSRMLS_DC) /* {{{ */
{
unsigned char *ptr = NULL;
zend_op *opline;
opline->op2 = *function_name;
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));
- }
- }
+ if (prefix_len) {
+ /* In run-time PHP will check for function with full name and
+ internal function with short name */
+ opline->op1.op_type = IS_CONST;
+ ZVAL_LONG(&opline->op1.u.constant, prefix_len);
+ } else {
+ SET_UNUSED(opline->op1);
}
zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(zend_function *));
compound.s = memchr(Z_STRVAL(class_name->u.constant), ':', Z_STRLEN(class_name->u.constant));
}
if (compound.v) {
+ /* This is a compound class name that cotains namespace prefix */
if (Z_TYPE(class_name->u.constant) == IS_UNICODE &&
Z_USTRVAL(class_name->u.constant)[0] == ':') {
+ /* The unicode name has "::" prefix */
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_STRVAL(class_name->u.constant)[0] == ':') {
+ /* The STRING name has "::" prefix */
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(
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);
}
+ /* Check if first part of compound name is an import name */
if (zend_u_hash_find(CG(current_import), Z_TYPE(class_name->u.constant), lcname, lcname_len+1, (void**)&ns) == SUCCESS) {
+ /* Substitute import name */
tmp.op_type = IS_CONST;
tmp.u.constant = **ns;
zval_copy_ctor(&tmp.u.constant);
*class_name = tmp;
}
efree(lcname.v);
- }
+ }
} else if (CG(current_import) || CG(current_namespace)) {
+ /* this is a plain name (without ::) */
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) {
+ /* The given name is an import name. Substitute it. */
zval_dtor(&class_name->u.constant);
class_name->u.constant = **ns;
zval_copy_ctor(&class_name->u.constant);
if (ns_lcname_len == lcname_len &&
memcmp(lcname.v, ns_lcname.v, UG(unicode)?UBYTES(lcname_len):lcname_len) == 0) {
+ /* The given name is equal to name of current namespace.
+ PHP will need to perform additional cheks at run-time to
+ determine if we assume namespace or class name. */
*fetch_type |= ZEND_FETCH_CLASS_RT_NS_NAME;
}
efree(ns_lcname.v);
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) {
+ /* There is an internal class with the same name exists.
+ PHP will need to perform additional cheks at run-time to
+ determine if we assume class in current namespace or
+ internal one. */
*fetch_type |= ZEND_FETCH_CLASS_RT_NS_CHECK;
}
tmp.op_type = IS_CONST;
unsigned char *ptr = NULL;
zend_op *opline;
ulong fetch_type = 0;
-
+
if (method_name->op_type == IS_CONST) {
zstr lcname;
unsigned int lcname_len;
if (class_node.op_type == IS_CONST &&
method_name->op_type == IS_CONST) {
- /* Prebuild ns::func name to speedup run-time check */
+ /* Prebuild ns::func name to speedup run-time check.
+ The additional names are stored in additional OP_DATA opcode. */
zstr fname, lcname;
unsigned int len, lcname_len;
opline->opcode = ZEND_OP_DATA;
opline->op1.op_type = IS_CONST;
SET_UNUSED(opline->op2);
-
+
len = Z_UNILEN(class_node.u.constant) + 2 + Z_UNILEN(method_name->u.constant);
if (UG(unicode)) {
fname.u = eumalloc(len + 1);
efree(fname.v);
if (fetch_type & ZEND_FETCH_CLASS_RT_NS_NAME) {
+ /* Prebuild name without first part of compound name for cases
+ when name is equal to current namespace name. This will speedup
+ runtime check. */
zstr colon;
if (UG(unicode) && (colon.u = u_memchr(lcname.u, ':', lcname_len)) && colon.u[1] == ':') {
colon.s += 2;
opline->op2.op_type = IS_CONST;
ZVAL_STRINGL(&opline->op2.u.constant, colon.s, lcname_len - (colon.s - lcname.s), 1);
- }
+ }
}
}
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];
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));
}
+ /* Class name must not conflict with import names */
if (CG(current_import) &&
zend_u_hash_exists(CG(current_import), Z_TYPE(class_name->u.constant), lcname, lcname_len+1)) {
zend_error(E_COMPILE_ERROR, "Class name '%R' coflicts with import name", Z_TYPE(class_name->u.constant), Z_UNIVAL(class_name->u.constant));
}
if (CG(current_namespace)) {
+ /* Prefix class name with name of current namespace */
znode tmp;
tmp.u.constant = *CG(current_namespace);
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;
void zend_do_build_namespace_name(znode *result, znode *prefix, znode *name TSRMLS_DC) /* {{{ */
{
int len;
-
+
if (prefix) {
*result = *prefix;
} else {
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");
+ 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) &&
if (new_name) {
name = &new_name->u.constant;
} else {
+ /* The form "import A::B" is eqivalent to "import A::B as B".
+ So we extract the last part of compound name ti use as a new_name */
name = &tmp;
if (UG(unicode)) {
UChar *p = u_memrchr(Z_USTRVAL_P(ns), ':', Z_USTRLEN_P(ns));
*name = *ns;
zval_copy_ctor(name);
warn = 1;
- }
+ }
} else {
char *p = zend_memrchr(Z_STRVAL_P(ns), ':', Z_STRLEN_P(ns));
if (p) {
*name = *ns;
zval_copy_ctor(name);
warn = 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_exists(CG(class_table), Z_TYPE_P(name), lcname, lcname_len+1)) {
zend_error(E_COMPILE_ERROR, "Import name '%R' coflicts with defined class", Z_TYPE_P(name), Z_UNIVAL_P(name));
}