Crosspost, hopefully silencing this issue for 5.* AND 6 will have an E_WARNING or even an E_ERROR on this.
helly Fri Feb 1 21:27:55 2008 UTC Modified files: (Branch: PHP_5_3) /php-src/ext/standard type.c /ZendEngine2 zend_API.c zend_API.h Log: [DOC] - Fix callable/static mess, the following will now all result in a E_STRICT . binding a dynamic function as a static callback . static call of a dynamic function . is_callable() on a static binding to a dynamic function # [EMAIL PROTECTED] PHP_5_3]$ php -a -d error_reporting=8191 # make: `sapi/cli/php' is up to date. # Interactive shell # # php > class t{ function f() { echo "Funny\n"; } } # php > $c = array("t","f"); # php > call_user_func($c); # # Strict Standards: call_user_func() expects parameter 1 to be a valid callback, non-static method t::f() cannot be called statically in php shell code on line 1 # Funny # php > var_dump(is_callable($c)); # # Strict Standards: Non-static method t::f() cannot be called statically in php shell code on line 1 # bool(true) # php > t::f(); # # Strict Standards: Non-static method t::f() should not be called statically in php shell code on line 1 # Funny # php >
http://cvs.php.net/viewvc.cgi/php-src/ext/standard/type.c?r1=1.30.2.2.2.3.2.2&r2=1.30.2.2.2.3.2.3&diff_format=u Index: php-src/ext/standard/type.c diff -u php-src/ext/standard/type.c:1.30.2.2.2.3.2.2 php-src/ext/standard/type.c:1.30.2.2.2.3.2.3 --- php-src/ext/standard/type.c:1.30.2.2.2.3.2.2 Thu Jan 31 11:21:15 2008 +++ php-src/ext/standard/type.c Fri Feb 1 21:27:55 2008 @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: type.c,v 1.30.2.2.2.3.2.2 2008/01/31 11:21:15 helly Exp $ */ +/* $Id: type.c,v 1.30.2.2.2.3.2.3 2008/02/01 21:27:55 helly Exp $ */ #include "php.h" #include "php_incomplete_class.h" @@ -374,7 +374,7 @@ syntax = Z_BVAL_PP(syntax_only); } - syntax = syntax ? IS_CALLABLE_CHECK_SYNTAX_ONLY : IS_CALLABLE_STRICT; + syntax = syntax ? IS_CALLABLE_CHECK_SYNTAX_ONLY : 0; if (argc > 2) { retval = zend_is_callable(*var, syntax, &name); zval_dtor(*callable_name); http://cvs.php.net/viewvc.cgi/ZendEngine2/zend_API.c?r1=1.296.2.27.2.34.2.17&r2=1.296.2.27.2.34.2.18&diff_format=u Index: ZendEngine2/zend_API.c diff -u ZendEngine2/zend_API.c:1.296.2.27.2.34.2.17 ZendEngine2/zend_API.c:1.296.2.27.2.34.2.18 --- ZendEngine2/zend_API.c:1.296.2.27.2.34.2.17 Thu Jan 24 10:49:26 2008 +++ ZendEngine2/zend_API.c Fri Feb 1 21:27:55 2008 @@ -18,13 +18,14 @@ +----------------------------------------------------------------------+ */ -/* $Id: zend_API.c,v 1.296.2.27.2.34.2.17 2008/01/24 10:49:26 dmitry Exp $ */ +/* $Id: zend_API.c,v 1.296.2.27.2.34.2.18 2008/02/01 21:27:55 helly Exp $ */ #include "zend.h" #include "zend_execute.h" #include "zend_API.h" #include "zend_modules.h" #include "zend_constants.h" +#include "zend_exceptions.h" #ifdef HAVE_STDARG_H #include <stdarg.h> @@ -311,7 +312,7 @@ } /* }}} */ -static char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, char **spec TSRMLS_DC) /* {{{ */ +static char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, char **spec, char **error, int *severity TSRMLS_DC) /* {{{ */ { char *spec_walk = *spec; char c = *spec_walk++; @@ -556,21 +557,15 @@ } if (ce_base) { if ((!*pce || !instanceof_function(*pce, ce_base TSRMLS_CC))) { - char *space; - char *class_name = get_active_class_name(&space TSRMLS_CC); - zend_error(E_WARNING, "%s%s%s() expects parameter %d to be a class name derived from %s, '%s' given", - class_name, space, get_active_function_name(TSRMLS_C), - arg_num, ce_base->name, Z_STRVAL_PP(arg)); + zend_spprintf(error, 0, "to be a class name derived from %s, '%s' given", + ce_base->name, Z_STRVAL_PP(arg)); *pce = NULL; return ""; } } if (!*pce) { - char *space; - char *class_name = get_active_class_name(&space TSRMLS_CC); - zend_error(E_WARNING, "%s%s%s() expects parameter %d to be a valid class name, '%s' given", - class_name, space, get_active_function_name(TSRMLS_C), - arg_num, Z_STRVAL_PP(arg)); + zend_spprintf(error, 0, "to be a valid class name, '%s' given", + Z_STRVAL_PP(arg)); return ""; } break; @@ -582,6 +577,7 @@ { zend_fcall_info *fci = va_arg(*va, zend_fcall_info *); zend_fcall_info_cache *fcc = va_arg(*va, zend_fcall_info_cache *); + char *is_callable_error = NULL; if (return_null) { fci->size = 0; @@ -589,10 +585,24 @@ break; } - if (zend_fcall_info_init(*arg, fci, fcc, NULL TSRMLS_CC) == SUCCESS) { + /* TODO(helly): Change to IS_CALLABLE_STRICT in next version */ + if (zend_fcall_info_init(*arg, 0, fci, fcc, NULL, &is_callable_error TSRMLS_CC) == SUCCESS) { + if (is_callable_error) { + *severity = E_STRICT; + zend_spprintf(error, 0, "to be a valid callback, %s", is_callable_error); + efree(is_callable_error); + return ""; + } break; } else { - return "valid callback"; + if (is_callable_error) { + *severity = E_WARNING; + zend_spprintf(error, 0, "to be a valid callback, %s", is_callable_error); + efree(is_callable_error); + return ""; + } else { + return "valid callback"; + } } } @@ -630,19 +640,28 @@ static int zend_parse_arg(int arg_num, zval **arg, va_list *va, char **spec, int quiet TSRMLS_DC) /* {{{ */ { - char *expected_type = NULL; + char *expected_type = NULL, *error = NULL; + int severity = E_WARNING; - expected_type = zend_parse_arg_impl(arg_num, arg, va, spec TSRMLS_CC); + expected_type = zend_parse_arg_impl(arg_num, arg, va, spec, &error, &severity TSRMLS_CC); if (expected_type) { - if (!quiet && *expected_type) { + if (!quiet && (*expected_type || error)) { char *space; char *class_name = get_active_class_name(&space TSRMLS_CC); - zend_error(E_WARNING, "%s%s%s() expects parameter %d to be %s, %s given", - class_name, space, get_active_function_name(TSRMLS_C), arg_num, expected_type, - zend_zval_type_name(*arg)); + if (error) { + zend_error(severity, "%s%s%s() expects parameter %d %s", + class_name, space, get_active_function_name(TSRMLS_C), arg_num, error); + efree(error); + } else { + zend_error(severity, "%s%s%s() expects parameter %d to be %s, %s given", + class_name, space, get_active_function_name(TSRMLS_C), arg_num, expected_type, + zend_zval_type_name(*arg)); + } + } + if (severity != E_STRICT) { + return FAILURE; } - return FAILURE; } return SUCCESS; @@ -2287,7 +2306,7 @@ } /* }}} */ -static int zend_is_callable_check_func(int check_flags, zval ***zobj_ptr_ptr, zend_class_entry *ce_org, zval *callable, zend_class_entry **ce_ptr, zend_function **fptr_ptr TSRMLS_DC) /* {{{ */ +static int zend_is_callable_check_func(int check_flags, zval ***zobj_ptr_ptr, zend_class_entry *ce_org, zval *callable, zend_class_entry **ce_ptr, zend_function **fptr_ptr, char **error TSRMLS_DC) /* {{{ */ { int retval; char *lmname, *colon; @@ -2330,6 +2349,7 @@ lmname = colon + 2; if (colon == Z_STRVAL_P(callable)) { + if (error) zend_spprintf(error, 0, "invalid function name"); return 0; } @@ -2337,10 +2357,14 @@ * Try to fetch class and then find static method. */ *ce_ptr = zend_fetch_class(Z_STRVAL_P(callable), clen, ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_SILENT TSRMLS_CC); if (!*ce_ptr) { + char *cname = estrndup(Z_STRVAL_P(callable), clen); + if (error) zend_spprintf(error, 0, "class '%s' not found", cname); + efree(cname); return 0; } ftable = &(*ce_ptr)->function_table; if (ce_org && !instanceof_function(ce_org, *ce_ptr TSRMLS_CC)) { + if (error) zend_spprintf(error, 0, "class '%s' is not a subclass of '%s'", ce_org->name, (*ce_ptr)->name); return 0; } lmname = zend_str_tolower_dup(Z_STRVAL_P(callable) + clen + 2, mlen); @@ -2352,6 +2376,7 @@ *ce_ptr = 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)[0]); return 0; } @@ -2364,6 +2389,12 @@ } else if (!*zobj_ptr_ptr && *ce_ptr && (*ce_ptr)->__callstatic) { retval = 1; *fptr_ptr = (*ce_ptr)->__callstatic; + } else { + if (*ce_ptr) { + if (error) zend_spprintf(error, 0, "class '%s' does not have a method '%s'", (*ce_ptr)->name, lmname); + } else { + if (error) zend_spprintf(error, 0, "function '%s' does not exist", lmname); + } } } else { *fptr_ptr = fptr; @@ -2371,11 +2402,18 @@ if (!*zobj_ptr_ptr && !(fptr->common.fn_flags & ZEND_ACC_STATIC)) { if ((check_flags & IS_CALLABLE_CHECK_IS_STATIC) != 0) { retval = 0; - } else { - if (EG(This) && instanceof_function(Z_OBJCE_P(EG(This)), *ce_ptr TSRMLS_CC)) { - *zobj_ptr_ptr = &EG(This); + } + if (EG(This) && instanceof_function(Z_OBJCE_P(EG(This)), *ce_ptr TSRMLS_CC)) { + *zobj_ptr_ptr = &EG(This); + if (error) { + zend_spprintf(error, 0, "non-static method %s::%s() cannot be called statically, assuming $this from compatible context %s", (*ce_ptr)->name, fptr->common.function_name, Z_OBJCE_P(EG(This))->name); + } else if (retval) { zend_error(E_STRICT, "Non-static method %s::%s() cannot be called statically, assuming $this from compatible context %s", (*ce_ptr)->name, fptr->common.function_name, Z_OBJCE_P(EG(This))->name); - } else { + } + } else { + if (error) { + zend_spprintf(error, 0, "non-static method %s::%s() cannot be called statically", (*ce_ptr)->name, fptr->common.function_name); + } else if (retval) { zend_error(E_STRICT, "Non-static method %s::%s() cannot be called statically", (*ce_ptr)->name, fptr->common.function_name); } } @@ -2383,10 +2421,12 @@ if (retval && (check_flags & IS_CALLABLE_CHECK_NO_ACCESS) == 0) { if (fptr->op_array.fn_flags & ZEND_ACC_PRIVATE) { if (!zend_check_private(fptr, *zobj_ptr_ptr ? Z_OBJCE_PP(*zobj_ptr_ptr) : EG(scope), lmname, mlen TSRMLS_CC)) { + if (error) zend_spprintf(error, 0, "cannot access private method %s::%s()", (*ce_ptr)->name, fptr->common.function_name); retval = 0; } } else if ((fptr->common.fn_flags & ZEND_ACC_PROTECTED)) { if (!zend_check_protected(fptr->common.scope, EG(scope))) { + if (error) zend_spprintf(error, 0, "cannot access protected method %s::%s()", (*ce_ptr)->name, fptr->common.function_name); retval = 0; } } @@ -2398,7 +2438,7 @@ } /* }}} */ -ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, char **callable_name, int *callable_name_len, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zval ***zobj_ptr_ptr TSRMLS_DC) /* {{{ */ +ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, char **callable_name, int *callable_name_len, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zval ***zobj_ptr_ptr, char **error TSRMLS_DC) /* {{{ */ { char *lcname; int callable_name_len_local; @@ -2421,6 +2461,9 @@ if (zobj_ptr_ptr == NULL) { zobj_ptr_ptr = &zobj_ptr_local; } + if (error) { + *error = NULL; + } *ce_ptr = NULL; *fptr_ptr = NULL; *zobj_ptr_ptr = NULL; @@ -2435,17 +2478,19 @@ return 1; } - return zend_is_callable_check_func(check_flags|IS_CALLABLE_CHECK_IS_STATIC, zobj_ptr_ptr, NULL, callable, ce_ptr, fptr_ptr TSRMLS_CC); + return zend_is_callable_check_func(check_flags|IS_CALLABLE_CHECK_IS_STATIC, zobj_ptr_ptr, NULL, callable, ce_ptr, fptr_ptr, error TSRMLS_CC); case IS_ARRAY: { zend_class_entry *ce = NULL; - zval **method; - zval **obj; + zval **method = NULL; + zval **obj = NULL; - if (zend_hash_num_elements(Z_ARRVAL_P(callable)) == 2 && - zend_hash_index_find(Z_ARRVAL_P(callable), 0, (void **) &obj) == SUCCESS && - zend_hash_index_find(Z_ARRVAL_P(callable), 1, (void **) &method) == SUCCESS && + if (zend_hash_num_elements(Z_ARRVAL_P(callable)) == 2) { + zend_hash_index_find(Z_ARRVAL_P(callable), 0, (void **) &obj); + zend_hash_index_find(Z_ARRVAL_P(callable), 1, (void **) &method); + } + if (obj && method && (Z_TYPE_PP(obj) == IS_OBJECT || Z_TYPE_PP(obj) == IS_STRING) && Z_TYPE_PP(method) == IS_STRING) { @@ -2508,11 +2553,24 @@ } if (ce) { - return zend_is_callable_check_func(check_flags, zobj_ptr_ptr, ce, *method, ce_ptr, fptr_ptr TSRMLS_CC); + return zend_is_callable_check_func(check_flags, zobj_ptr_ptr, ce, *method, ce_ptr, fptr_ptr, error TSRMLS_CC); + } else { + if (error) zend_spprintf(error, 0, "first array member is not a valid %s", Z_TYPE_PP(obj) == IS_STRING ? "class name" : "object"); + } + } else { + if (zend_hash_num_elements(Z_ARRVAL_P(callable)) == 2) { + if (!obj) { + if (error) zend_spprintf(error, 0, "first array member is not a valid class name or object"); + } else { + if (error) zend_spprintf(error, 0, "second array member is not a valid method"); + } + } else { + if (error) zend_spprintf(error, 0, "array must have exactly two members"); + } + if (callable_name) { + *callable_name = estrndup("Array", sizeof("Array")-1); + *callable_name_len = sizeof("Array") - 1; } - } else if (callable_name) { - *callable_name = estrndup("Array", sizeof("Array")-1); - *callable_name_len = sizeof("Array") - 1; } *ce_ptr = ce; } @@ -2528,6 +2586,7 @@ *callable_name_len = Z_STRLEN(expr_copy); zval_dtor(&expr_copy); } + if (error) zend_spprintf(error, 0, "no array or string given"); return 0; } } @@ -2537,7 +2596,7 @@ { TSRMLS_FETCH(); - return zend_is_callable_ex(callable, check_flags, callable_name, NULL, NULL, NULL, NULL TSRMLS_CC); + return zend_is_callable_ex(callable, check_flags, callable_name, NULL, NULL, NULL, NULL, NULL TSRMLS_CC); } /* }}} */ @@ -2547,7 +2606,7 @@ zend_function *fptr; zval **zobj_ptr; - if (zend_is_callable_ex(callable, 0, callable_name, NULL, &ce, &fptr, &zobj_ptr TSRMLS_CC)) { + if (zend_is_callable_ex(callable, IS_CALLABLE_STRICT, callable_name, NULL, &ce, &fptr, &zobj_ptr, NULL TSRMLS_CC)) { if (Z_TYPE_P(callable) == IS_STRING && ce) { zval_dtor(callable); array_init(callable); @@ -2560,7 +2619,7 @@ } /* }}} */ -ZEND_API int zend_fcall_info_init(zval *callable, zend_fcall_info *fci, zend_fcall_info_cache *fcc, char **callable_name TSRMLS_DC) /* {{{ */ +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) /* {{{ */ { int lc_len; char *lcname; @@ -2568,7 +2627,7 @@ zend_function *func; zval **obj; - if (!zend_is_callable_ex(callable, IS_CALLABLE_STRICT, callable_name, NULL, &ce, &func, &obj TSRMLS_CC)) { + if (!zend_is_callable_ex(callable, check_flags, callable_name, NULL, &ce, &func, &obj, error TSRMLS_CC)) { return FAILURE; } http://cvs.php.net/viewvc.cgi/ZendEngine2/zend_API.h?r1=1.207.2.8.2.8.2.7&r2=1.207.2.8.2.8.2.8&diff_format=u Index: ZendEngine2/zend_API.h diff -u ZendEngine2/zend_API.h:1.207.2.8.2.8.2.7 ZendEngine2/zend_API.h:1.207.2.8.2.8.2.8 --- ZendEngine2/zend_API.h:1.207.2.8.2.8.2.7 Thu Jan 24 18:07:45 2008 +++ ZendEngine2/zend_API.h Fri Feb 1 21:27:55 2008 @@ -18,7 +18,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: zend_API.h,v 1.207.2.8.2.8.2.7 2008/01/24 18:07:45 dmitry Exp $ */ +/* $Id: zend_API.h,v 1.207.2.8.2.8.2.8 2008/02/01 21:27:55 helly Exp $ */ #ifndef ZEND_API_H #define ZEND_API_H @@ -228,7 +228,7 @@ #define IS_CALLABLE_STRICT (IS_CALLABLE_CHECK_IS_STATIC) -ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, char **callable_name, int *callable_name_len, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zval ***zobj_ptr_ptr TSRMLS_DC); +ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, char **callable_name, int *callable_name_len, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zval ***zobj_ptr_ptr, char **error TSRMLS_DC); ZEND_API zend_bool zend_is_callable(zval *callable, uint check_flags, char **callable_name); ZEND_API zend_bool zend_make_callable(zval *callable, char **callable_name TSRMLS_DC); ZEND_API const char *zend_get_module_version(const char *module_name); @@ -409,8 +409,9 @@ * fci->param_count = 0; * fci->params = NULL; * The callable_name argument may be NULL. + * Set check_flags to IS_CALLABLE_STRICT for every new usage! */ -ZEND_API int zend_fcall_info_init(zval *callable, zend_fcall_info *fci, zend_fcall_info_cache *fcc, char **callable_name TSRMLS_DC); +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); /** Clear argumens connected with zend_fcall_info *fci * If free_mem is not zero then the params array gets free'd as well
-- Zend Engine CVS Mailing List (http://cvs.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php
-- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php