]> granicus.if.org Git - php/commitdiff
- MFB static callable message mess
authorMarcus Boerger <helly@php.net>
Sat, 2 Feb 2008 15:23:22 +0000 (15:23 +0000)
committerMarcus Boerger <helly@php.net>
Sat, 2 Feb 2008 15:23:22 +0000 (15:23 +0000)
Zend/zend_API.c
Zend/zend_API.h
Zend/zend_execute_API.c
Zend/zend_vm_def.h

index 07e47ded71421fb47d8aaa8377ceb9faa558a76d..3613c9eec901d5b599303ad84d7ce34710ce4662 100644 (file)
@@ -25,6 +25,7 @@
 #include "zend_API.h"
 #include "zend_modules.h"
 #include "zend_constants.h"
+#include "zend_exceptions.h"
 
 #ifdef HAVE_STDARG_H
 #include <stdarg.h>
@@ -313,7 +314,7 @@ static int parse_arg_object_to_string(zval **arg, char **p, int *pl, int type TS
 }
 /* }}} */
 
-static char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, char **spec, char T_arg_type, int* ret_type TSRMLS_DC) /* {{{ */
+static char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, char **spec, char T_arg_type, int* ret_type, char **error, int *severity TSRMLS_DC) /* {{{ */
 {
        char *spec_walk = *spec;
        char c = *spec_walk++;
@@ -770,21 +771,15 @@ static char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, char **sp
                                }
                                if (ce_base) {
                                        if ((!*pce || !instanceof_function(*pce, ce_base TSRMLS_CC))) {
-                                               char *space;
-                                               zstr class_name = get_active_class_name(&space TSRMLS_CC);
-                                               zend_error(E_WARNING, "%v%s%v() expects parameter %d to be a class name derived from %v, '%v' 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;
-                                       zstr class_name = get_active_class_name(&space TSRMLS_CC);
-                                       zend_error(E_WARNING, "%v%s%v() expects parameter %d to be a valid class name, '%v' 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;
@@ -796,6 +791,7 @@ static char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, char **sp
                        {
                                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;
@@ -803,10 +799,24 @@ static char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, char **sp
                                        break;
                                }
 
-                               if (zend_fcall_info_init(*arg, fci, fcc, NULL TSRMLS_CC) == SUCCESS) {
+                               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);
+                                               *spec = spec_walk;
+                                               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";
+                                       }
                                }
                        }
 
@@ -844,20 +854,29 @@ static char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, char **sp
 
 static int zend_parse_arg(int arg_num, zval **arg, va_list *va, char **spec, int quiet, char T_arg_type TSRMLS_DC) /* {{{ */
 {
-       char *expected_type = NULL;
+       char *expected_type = NULL, *error = NULL;
        int ret_type = IS_STRING;
+       int severity = E_WARNING;
 
-       expected_type = zend_parse_arg_impl(arg_num, arg, va, spec, T_arg_type, &ret_type TSRMLS_CC);
+       expected_type = zend_parse_arg_impl(arg_num, arg, va, spec, T_arg_type, &ret_type, &error, &severity TSRMLS_CC);
        if (expected_type) {
-               if (!quiet && *expected_type) {
+               if (!quiet && (*expected_type || error)) {
                        char *space;
                        zstr class_name = get_active_class_name(&space TSRMLS_CC);
 
-                       zend_error(E_WARNING, "%v%s%v() expects parameter %d to be %R, %s given",
-                                       class_name, space, get_active_function_name(TSRMLS_C), arg_num, ret_type, expected_type,
-                                       zend_zval_type_name(*arg));
+                       if (error) {
+                               zend_error(severity, "%v%s%v() expects parameter %d %s",
+                                               class_name, space, get_active_function_name(TSRMLS_C), arg_num, error);
+                               efree(error);
+                       } else {
+                               zend_error(severity, "%v%s%v() expects parameter %d to be %R, %s given",
+                                               class_name, space, get_active_function_name(TSRMLS_C), arg_num, ret_type, expected_type,
+                                               zend_zval_type_name(*arg));
+                       }
+               }
+               if (severity != E_STRICT) {
+                       return FAILURE;
                }
-               return FAILURE;
        }
 
        return SUCCESS;
@@ -2625,7 +2644,7 @@ ZEND_API int zend_disable_class(char *class_name, uint class_name_length TSRMLS_
 }
 /* }}} */
 
-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;
        zstr lmname, mname, colon = NULL_ZSTR;
@@ -2686,6 +2705,7 @@ static int zend_is_callable_check_func(int check_flags, zval ***zobj_ptr_ptr, ze
                        colon.s--;
                        clen = colon.s - Z_STRVAL_P(callable);
                        if (clen == 0) {
+                               if (error) zend_spprintf(error, 0, "invalid function name");
                                return 0;
                        }
                        mlen = Z_STRLEN_P(callable) - clen - 2;
@@ -2699,10 +2719,14 @@ static int zend_is_callable_check_func(int check_flags, zval ***zobj_ptr_ptr, ze
                 * 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 | 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_u_str_case_fold(Z_TYPE_P(callable), mname, mlen, 1, &mlen);
@@ -2713,6 +2737,7 @@ static int zend_is_callable_check_func(int check_flags, zval ***zobj_ptr_ptr, ze
                *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));
                return 0;
        }
 
@@ -2725,24 +2750,53 @@ static int zend_is_callable_check_func(int check_flags, zval ***zobj_ptr_ptr, ze
                } 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;
                if (*ce_ptr) {
                        if (!*zobj_ptr_ptr && !(fptr->common.fn_flags & ZEND_ACC_STATIC)) {
+                               int severity;
+                               char *verb;
+                               if (fptr->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
+                                       severity = E_STRICT;
+                                       verb = "should not";
+                               } else {
+                                       severity = E_ERROR;
+                                       verb = "cannot";
+                               }
                                if ((check_flags & IS_CALLABLE_CHECK_IS_STATIC) != 0) {
                                        retval = 0;
+                               }
+                               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() %s be called statically, assuming $this from compatible context %s", (*ce_ptr)->name, fptr->common.function_name, verb, Z_OBJCE_P(EG(This))->name);
+                                       } else if (retval) {
+                                               zend_error(severity, "Non-static method %s::%s() %s be called statically, assuming $this from compatible context %s", (*ce_ptr)->name, fptr->common.function_name, verb, Z_OBJCE_P(EG(This))->name);
+                                       }
                                } else {
-                                       zend_error(E_STRICT, "Non-static method %v::%v() cannot be called statically", (*ce_ptr)->name, fptr->common.function_name);
+                                       if (error) {
+                                               zend_spprintf(error, 0, "non-static method %s::%s() %s be called statically", (*ce_ptr)->name, fptr->common.function_name, verb);
+                                       } else if (retval) {
+                                               zend_error(severity, "Non-static method %s::%s() %s be called statically", (*ce_ptr)->name, fptr->common.function_name, verb);
+                                       }
                                }
                        }
                        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;
                                        }
                                }
@@ -2754,7 +2808,7 @@ static int zend_is_callable_check_func(int check_flags, zval ***zobj_ptr_ptr, ze
 }
 /* }}} */
 
-ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, zval *callable_name, 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, zval *callable_name, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zval ***zobj_ptr_ptr, char **error TSRMLS_DC) /* {{{ */
 {
        zstr lcname;
        unsigned int lcname_len;
@@ -2774,6 +2828,9 @@ ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, zval *c
        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;
@@ -2790,7 +2847,7 @@ ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, zval *c
                                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, zobj_ptr_ptr, NULL, callable, ce_ptr, fptr_ptr, error TSRMLS_CC);
 
                case IS_ARRAY:
                        {
@@ -2935,10 +2992,23 @@ ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, zval *c
                                        }
 
                                        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) {
+                                               ZVAL_ASCII_STRINGL(callable_name, "Array", sizeof("Array")-1, 1);
                                        }
-                               } else if (callable_name) {
-                                       ZVAL_ASCII_STRINGL(callable_name, "Array", sizeof("Array")-1, 1);
                                }
                                *ce_ptr = ce;
                        }
@@ -2950,6 +3020,7 @@ ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, zval *c
                                zval_copy_ctor(callable_name);
                                convert_to_text(callable_name);
                        }
+                       if (error) zend_spprintf(error, 0, "no array or string given");
                        return 0;
        }
 }
@@ -2959,52 +3030,36 @@ ZEND_API zend_bool zend_is_callable(zval *callable, uint check_flags, zval *call
 {
        TSRMLS_FETCH();
 
-       return zend_is_callable_ex(callable, check_flags, callable_name, NULL, NULL, NULL TSRMLS_CC);
+       return zend_is_callable_ex(callable, check_flags, callable_name, NULL, NULL, NULL, NULL TSRMLS_CC);
 }
 /* }}} */
 
 ZEND_API zend_bool zend_make_callable(zval *callable, zval *callable_name TSRMLS_DC) /* {{{ */
 {
-       char *lcname, *func, *class_name;
-       zend_bool retval = 0;
-       zend_class_entry **pce;
-       int class_name_len;
+       zend_class_entry *ce;
+       zend_function *fptr;
+       zval **zobj_ptr;
 
-       if (zend_is_callable_ex(callable, IS_CALLABLE_STRICT, callable_name, NULL, NULL, NULL TSRMLS_CC)) {
+       if (zend_is_callable_ex(callable, IS_CALLABLE_STRICT, callable_name, &ce, &fptr, &zobj_ptr, NULL TSRMLS_CC)) {
+               if ((Z_TYPE_P(callable) == IS_STRING || Z_TYPE_P(callable) == IS_UNICODE) && ce) {
+                       zval_dtor(callable);
+                       array_init(callable);
+                       add_next_index_text(callable, ce->name, 1);
+                       add_next_index_text(callable, fptr->common.function_name, 1);
+               }
                return 1;
        }
-       switch (Z_TYPE_P(callable)) {
-               case IS_STRING:
-                       lcname = zend_str_tolower_dup(Z_STRVAL_P(callable), Z_STRLEN_P(callable));
-
-                       if ((func = strstr(lcname, "::")) != NULL) {
-                               *func = '\0';
-                               class_name_len = func - lcname;
-                               class_name = estrndup(Z_STRVAL_P(callable), class_name_len);
-                               if (zend_lookup_class(class_name, class_name_len, &pce TSRMLS_CC) == SUCCESS) {
-                                       zval_dtor(callable);
-                                       array_init(callable);
-                                       add_next_index_stringl(callable, lcname, class_name_len, 1);
-                                       func += 2;
-                                       add_next_index_stringl(callable, func, strlen(func), 1);
-                                       retval = 1;
-                               }
-                               efree(class_name);
-                       }
-                       efree(lcname);
-                       break;
-       }
-       return retval;
+       return 0;
 }
 /* }}} */
 
-ZEND_API int zend_fcall_info_init(zval *callable, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zval *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, zval *callable_name, char **error TSRMLS_DC) /* {{{ */
 {
        zend_class_entry *ce;
        zend_function *func;
        zval **obj;
 
-       if (!zend_is_callable_ex(callable, IS_CALLABLE_STRICT, callable_name, &ce, &func, &obj TSRMLS_CC)) {
+       if (!zend_is_callable_ex(callable, check_flags, callable_name, &ce, &func, &obj, error TSRMLS_CC)) {
                return FAILURE;
        }
 
index 7aa24150a2395b93326a22f05480f830e790dc6e..7d0c8895a375f68bf5d6016395fd97b06ac2df4f 100644 (file)
@@ -233,7 +233,7 @@ ZEND_API void zend_wrong_param_count(TSRMLS_D);
 
 #define IS_CALLABLE_STRICT  (IS_CALLABLE_CHECK_IS_STATIC)
 
-ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, zval *callable_name, 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, zval *callable_name, 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, zval *callable_name);
 ZEND_API zend_bool zend_make_callable(zval *callable, zval *callable_name TSRMLS_DC);
 ZEND_API const char *zend_get_module_version(const char *module_name);
@@ -1534,8 +1534,9 @@ ZEND_API extern zend_fcall_info_cache empty_fcall_info_cache;
  * 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, zval *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, zval *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
index ee0fbaa62eb12a4c3a1be8d2822614d83a764694..cec985c7be776bfb610284e94312d16ab3bd9c43 100644 (file)
@@ -1145,12 +1145,15 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS
                EG(This) = NULL;
                if (calling_scope && !(EX(function_state).function->common.fn_flags & ZEND_ACC_STATIC)) {
                        int severity;
+                       char *verb;
                        if (EX(function_state).function->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
                                severity = E_STRICT;
+                               verb = "should not";
                        } else {
                                severity = E_ERROR;
+                               verb = "cannot";
                        }
-                       zend_error(severity, "Non-static method %v::%v() cannot be called statically", calling_scope->name, EX(function_state).function->common.function_name);
+                       zend_error(severity, "Non-static method %v::%v() %s be called statically", calling_scope->name, EX(function_state).function->common.function_name, verb);
                }
        }
 
index e2f8e853c1c20124b7eff7f0b57fa49642027718..9c5861312483d9445ee509c8e701522b1bbef9e2 100644 (file)
@@ -2026,7 +2026,16 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMP|VAR|UNUS
                    !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);
+                       int severity;
+                       char *verb;
+                       if (EX(fbc)->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
+                               severity = E_STRICT;
+                               verb = "should not";
+                       } else {
+                               severity = E_ERROR;
+                               verb = "cannot";
+                       }
+                       zend_error(severity, "Non-static method %v::%v() %s be called statically, assuming $this from incompatible context", EX(fbc)->common.scope->name, EX(fbc)->common.function_name, verb);
 
                }
                if ((EX(object) = EG(This))) {