diff options
author | Dmitry Stogov <dmitry@php.net> | 2008-07-26 13:14:04 +0000 |
---|---|---|
committer | Dmitry Stogov <dmitry@php.net> | 2008-07-26 13:14:04 +0000 |
commit | af05ce0af6d35e668de297fc4961fa738272f13c (patch) | |
tree | 32d1f47915557308aa7e2f9212abb3a572b4b207 /Zend/zend_API.c | |
parent | 77baec3f6d57f2d37e89aceb758c6adf6a9538f6 (diff) | |
download | php-git-af05ce0af6d35e668de297fc4961fa738272f13c.tar.gz |
Fixed is_callable/call_user_func mess that had done different things for very similar arguments e.g. array("A","B") and "A::B"
Diffstat (limited to 'Zend/zend_API.c')
-rw-r--r-- | Zend/zend_API.c | 162 |
1 files changed, 113 insertions, 49 deletions
diff --git a/Zend/zend_API.c b/Zend/zend_API.c index cc30df3ca7..2ec10b8239 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -2318,6 +2318,9 @@ static int zend_is_callable_check_class(char *name, int name_len, zend_fcall_inf } else { fcc->called_scope = EG(called_scope); fcc->calling_scope = EG(scope); + if (!fcc->object_pp) { + fcc->object_pp = EG(This) ? &EG(This) : NULL; + } ret = 1; } } else if (name_len == sizeof("parent") - 1 && @@ -2329,6 +2332,9 @@ static int zend_is_callable_check_class(char *name, int name_len, zend_fcall_inf } else { fcc->called_scope = EG(called_scope); fcc->calling_scope = EG(scope)->parent; + if (!fcc->object_pp) { + fcc->object_pp = EG(This) ? &EG(This) : NULL; + } ret = 1; } } else if (name_len == sizeof("static") - 1 && @@ -2338,10 +2344,23 @@ static int zend_is_callable_check_class(char *name, int name_len, zend_fcall_inf } else { fcc->called_scope = EG(called_scope); fcc->calling_scope = EG(called_scope); + if (!fcc->object_pp) { + fcc->object_pp = EG(This) ? &EG(This) : NULL; + } ret = 1; } } else if (zend_lookup_class_ex(name, name_len, 1, &pce TSRMLS_CC) == SUCCESS) { - fcc->called_scope = fcc->calling_scope = *pce; + zend_class_entry *scope = EG(active_op_array) ? EG(active_op_array)->scope : NULL; + + fcc->calling_scope = *pce; + if (scope && !fcc->object_pp && EG(This) && + instanceof_function(Z_OBJCE_P(EG(This)), scope TSRMLS_CC) && + instanceof_function(scope, fcc->calling_scope TSRMLS_CC)) { + fcc->object_pp = &EG(This); + fcc->called_scope = Z_OBJCE_PP(fcc->object_pp); + } else { + fcc->called_scope = fcc->object_pp ? Z_OBJCE_PP(fcc->object_pp) : fcc->calling_scope; + } ret = 1; } else { if (error) zend_spprintf(error, 0, "class '%.*s' not found", name_len, name); @@ -2355,8 +2374,8 @@ static int zend_is_callable_check_class(char *name, int name_len, zend_fcall_inf static int zend_is_callable_check_func(int check_flags, zval *callable, zend_fcall_info_cache *fcc, char **error TSRMLS_DC) /* {{{ */ { zend_class_entry *ce_org = fcc->calling_scope; - int retval; - char *lmname, *colon; + int retval = 0; + char *mname, *lmname, *colon; int clen, mlen; zend_class_entry *last_scope; HashTable *ftable; @@ -2375,9 +2394,11 @@ static int zend_is_callable_check_func(int check_flags, zval *callable, zend_fca Z_STRVAL_P(callable)[1] == ':' ) { mlen = Z_STRLEN_P(callable) - 2; + mname = Z_STRVAL_P(callable) + 2; lmname = zend_str_tolower_dup(Z_STRVAL_P(callable) + 2, mlen); } else { mlen = Z_STRLEN_P(callable); + mname = Z_STRVAL_P(callable); lmname = zend_str_tolower_dup(Z_STRVAL_P(callable), mlen); } /* Check if function with given name exists. @@ -2397,7 +2418,6 @@ static int zend_is_callable_check_func(int check_flags, zval *callable, zend_fca colon--; clen = colon - Z_STRVAL_P(callable); mlen = Z_STRLEN_P(callable) - clen - 2; - lmname = colon + 2; if (colon == Z_STRVAL_P(callable)) { if (error) zend_spprintf(error, 0, "invalid function name"); @@ -2422,53 +2442,41 @@ static int zend_is_callable_check_func(int check_flags, zval *callable, zend_fca if (error) zend_spprintf(error, 0, "class '%s' is not a subclass of '%s'", ce_org->name, fcc->calling_scope->name); return 0; } - lmname = zend_str_tolower_dup(Z_STRVAL_P(callable) + clen + 2, mlen); + mname = Z_STRVAL_P(callable) + clen + 2; } else if (ce_org) { /* Try to fetch find static method of given class. */ mlen = Z_STRLEN_P(callable); - lmname = zend_str_tolower_dup(Z_STRVAL_P(callable), Z_STRLEN_P(callable)); + mname = Z_STRVAL_P(callable); ftable = &ce_org->function_table; fcc->calling_scope = ce_org; } else { /* We already checked for plain function before. */ - if (error) zend_spprintf(error, 0, "function '%s' not found or invalid function name", Z_STRVAL_P(callable)); + if (error && !(check_flags & IS_CALLABLE_CHECK_SILENT)) { + zend_spprintf(error, 0, "function '%s' not found or invalid function name", Z_STRVAL_P(callable)); + } return 0; } - retval = zend_hash_find(ftable, lmname, mlen+1, (void**)&fcc->function_handler) == SUCCESS ? 1 : 0; - - if (!retval) { - if (fcc->object_pp && fcc->calling_scope && fcc->calling_scope->__call != 0) { - retval = 1; - call_via_handler = 1; - fcc->function_handler = fcc->calling_scope->__call; + lmname = zend_str_tolower_dup(mname, mlen); + if (zend_hash_find(ftable, lmname, mlen+1, (void**)&fcc->function_handler) == SUCCESS) { + retval = 1; + } else if (fcc->object_pp && Z_OBJ_HT_PP(fcc->object_pp)->get_method) { + fcc->function_handler = Z_OBJ_HT_PP(fcc->object_pp)->get_method(fcc->object_pp, mname, mlen TSRMLS_CC); + retval = fcc->function_handler ? 1 : 0; + call_via_handler = 1; + } else if (fcc->calling_scope) { + if (fcc->calling_scope->get_static_method) { + fcc->function_handler = fcc->calling_scope->get_static_method(fcc->calling_scope, mname, mlen TSRMLS_CC); } else { - if (!fcc->object_pp && fcc->calling_scope && (fcc->calling_scope->__callstatic || fcc->calling_scope->__call)) { - if (fcc->calling_scope->__call && - EG(This) && - Z_OBJ_HT_P(EG(This))->get_class_entry && - instanceof_function(Z_OBJCE_P(EG(This)), fcc->calling_scope TSRMLS_CC)) { - retval = 1; - call_via_handler = 1; - fcc->function_handler = fcc->calling_scope->__call; - fcc->object_pp = &EG(This); - } else if (fcc->calling_scope->__callstatic) { - retval = 1; - call_via_handler = 1; - fcc->function_handler = fcc->calling_scope->__callstatic; - } - } - - if (retval == 0) { - if (fcc->calling_scope) { - if (error) zend_spprintf(error, 0, "class '%s' does not have a method '%s'", fcc->calling_scope->name, lmname); - } else { - if (error) zend_spprintf(error, 0, "function '%s' does not exist", lmname); - } - } + fcc->function_handler = zend_std_get_static_method(fcc->calling_scope, mname, mlen TSRMLS_CC); } - } else { - if (fcc->calling_scope) { + retval = fcc->function_handler ? 1 : 0; + call_via_handler = 1; + } + efree(lmname); + + if (retval) { + if (fcc->calling_scope && !call_via_handler) { if (!fcc->object_pp && !(fcc->function_handler->common.fn_flags & ZEND_ACC_STATIC)) { int severity; char *verb; @@ -2500,7 +2508,7 @@ static int zend_is_callable_check_func(int check_flags, zval *callable, zend_fca } if (retval && (check_flags & IS_CALLABLE_CHECK_NO_ACCESS) == 0) { if (fcc->function_handler->op_array.fn_flags & ZEND_ACC_PRIVATE) { - if (!zend_check_private(fcc->function_handler, fcc->object_pp ? Z_OBJCE_PP(fcc->object_pp) : EG(scope), lmname, mlen TSRMLS_CC)) { + if (!zend_check_private(fcc->function_handler, fcc->object_pp ? Z_OBJCE_PP(fcc->object_pp) : EG(scope), mname, mlen TSRMLS_CC)) { if (error) { if (*error) { efree(*error); @@ -2522,20 +2530,26 @@ static int zend_is_callable_check_func(int check_flags, zval *callable, zend_fca } } } + } else if (error && !(check_flags & IS_CALLABLE_CHECK_SILENT)) { + if (fcc->calling_scope) { + if (error) zend_spprintf(error, 0, "class '%s' does not have a method '%s'", fcc->calling_scope->name, mname); + } else { + if (error) zend_spprintf(error, 0, "function '%s' does not exist", mname); + } } if (fcc->object_pp) { fcc->called_scope = Z_OBJCE_PP(fcc->object_pp); } - efree(lmname); - if (retval && !call_via_handler) { + if (retval) { fcc->initialized = 1; } return retval; } /* }}} */ -ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, char **callable_name, int *callable_name_len, zend_fcall_info_cache *fcc, char **error TSRMLS_DC) /* {{{ */ +ZEND_API zend_bool zend_is_callable_ex(zval *callable, zval **object_pp, uint check_flags, char **callable_name, int *callable_name_len, zend_fcall_info_cache *fcc, char **error TSRMLS_DC) /* {{{ */ { + zend_bool ret; int callable_name_len_local; zend_fcall_info_cache fcc_local; @@ -2561,15 +2575,42 @@ ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, char ** switch (Z_TYPE_P(callable)) { case IS_STRING: - if (callable_name) { + if (object_pp && *object_pp) { + fcc->object_pp = object_pp; + fcc->calling_scope = Z_OBJCE_PP(object_pp); + if (callable_name) { + char *ptr; + + *callable_name_len = fcc->calling_scope->name_length + Z_STRLEN_P(callable) + sizeof("::") - 1; + ptr = *callable_name = emalloc(*callable_name_len + 1); + memcpy(ptr, fcc->calling_scope->name, fcc->calling_scope->name_length); + ptr += fcc->calling_scope->name_length; + memcpy(ptr, "::", sizeof("::") - 1); + ptr += sizeof("::") - 1; + memcpy(ptr, Z_STRVAL_P(callable), Z_STRLEN_P(callable) + 1); + } + } else if (callable_name) { *callable_name = estrndup(Z_STRVAL_P(callable), Z_STRLEN_P(callable)); *callable_name_len = Z_STRLEN_P(callable); } if (check_flags & IS_CALLABLE_CHECK_SYNTAX_ONLY) { + fcc->called_scope = fcc->calling_scope; return 1; } - return zend_is_callable_check_func(check_flags, callable, fcc, error TSRMLS_CC); + ret = zend_is_callable_check_func(check_flags, callable, fcc, error TSRMLS_CC); + if (fcc == &fcc_local && + fcc->function_handler && + ((fcc->function_handler->type == ZEND_INTERNAL_FUNCTION && + (fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER)) || + fcc->function_handler->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY || + fcc->function_handler->type == ZEND_OVERLOADED_FUNCTION)) { + if (fcc->function_handler->type != ZEND_OVERLOADED_FUNCTION) { + efree(fcc->function_handler->common.function_name); + } + efree(fcc->function_handler); + } + return ret; case IS_ARRAY: { @@ -2629,7 +2670,20 @@ ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, char ** } } - return zend_is_callable_check_func(check_flags, *method, fcc, error TSRMLS_CC); + ret = zend_is_callable_check_func(check_flags, *method, fcc, error TSRMLS_CC); + if (fcc == &fcc_local && + fcc->function_handler && + ((fcc->function_handler->type == ZEND_INTERNAL_FUNCTION && + (fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER)) || + fcc->function_handler->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY || + fcc->function_handler->type == ZEND_OVERLOADED_FUNCTION)) { + if (fcc->function_handler->type != ZEND_OVERLOADED_FUNCTION) { + efree(fcc->function_handler->common.function_name); + } + efree(fcc->function_handler); + } + return ret; + } else { if (zend_hash_num_elements(Z_ARRVAL_P(callable)) == 2) { if (!obj || (Z_TYPE_PP(obj) != IS_STRING && Z_TYPE_PP(obj) != IS_OBJECT)) { @@ -2683,7 +2737,7 @@ ZEND_API zend_bool zend_is_callable(zval *callable, uint check_flags, char **cal { TSRMLS_FETCH(); - return zend_is_callable_ex(callable, check_flags, callable_name, NULL, NULL, NULL TSRMLS_CC); + return zend_is_callable_ex(callable, NULL, check_flags, callable_name, NULL, NULL, NULL TSRMLS_CC); } /* }}} */ @@ -2691,13 +2745,23 @@ ZEND_API zend_bool zend_make_callable(zval *callable, char **callable_name TSRML { zend_fcall_info_cache fcc; - if (zend_is_callable_ex(callable, IS_CALLABLE_STRICT, callable_name, NULL, &fcc, NULL TSRMLS_CC)) { + if (zend_is_callable_ex(callable, NULL, IS_CALLABLE_STRICT, callable_name, NULL, &fcc, NULL TSRMLS_CC)) { if (Z_TYPE_P(callable) == IS_STRING && fcc.calling_scope) { zval_dtor(callable); array_init(callable); add_next_index_string(callable, fcc.calling_scope->name, 1); add_next_index_string(callable, fcc.function_handler->common.function_name, 1); } + if (fcc.function_handler && + ((fcc.function_handler->type == ZEND_INTERNAL_FUNCTION && + (fcc.function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER)) || + fcc.function_handler->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY || + fcc.function_handler->type == ZEND_OVERLOADED_FUNCTION)) { + if (fcc.function_handler->type != ZEND_OVERLOADED_FUNCTION) { + efree(fcc.function_handler->common.function_name); + } + efree(fcc.function_handler); + } return 1; } return 0; @@ -2706,7 +2770,7 @@ ZEND_API zend_bool zend_make_callable(zval *callable, char **callable_name TSRML ZEND_API int zend_fcall_info_init(zval *callable, uint check_flags, zend_fcall_info *fci, zend_fcall_info_cache *fcc, char **callable_name, char **error TSRMLS_DC) /* {{{ */ { - if (!zend_is_callable_ex(callable, check_flags, callable_name, NULL, fcc, error TSRMLS_CC)) { + if (!zend_is_callable_ex(callable, NULL, check_flags, callable_name, NULL, fcc, error TSRMLS_CC)) { return FAILURE; } |