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

Reply via email to