]> granicus.if.org Git - php/commitdiff
Fixed is_callable/call_user_func mess that had done different things for very similar...
authorDmitry Stogov <dmitry@php.net>
Sat, 26 Jul 2008 13:14:56 +0000 (13:14 +0000)
committerDmitry Stogov <dmitry@php.net>
Sat, 26 Jul 2008 13:14:56 +0000 (13:14 +0000)
17 files changed:
Zend/tests/bug32290.phpt
Zend/tests/objects_027.phpt
Zend/zend_API.c
Zend/zend_API.h
Zend/zend_closures.c
Zend/zend_compile.h
Zend/zend_execute_API.c
Zend/zend_object_handlers.c
Zend/zend_vm_def.h
Zend/zend_vm_execute.h
ext/reflection/php_reflection.c
ext/spl/php_spl.c
ext/spl/tests/spl_autoload_007.phpt
ext/standard/tests/array/array_map_object1.phpt
ext/standard/tests/array/array_map_object3.phpt
ext/standard/tests/general_functions/bug40398.phpt
ext/standard/tests/general_functions/callbacks_001.phpt

index 169f269876c571e6beb365991d395acc38565adb..dc00ec8492cf2e45d410b3bf3b0515ca74524930 100755 (executable)
@@ -98,8 +98,6 @@ var_dump($x->doSomethingStatic(1));
 --EXPECTF--
 ===A===
 TestB::doSomething(1)
-
-Strict Standards: call_user_func_array() expects parameter 1 to be a valid callback, non-static method TestA::doSomething() should not be called statically, assuming $this from compatible context TestB in %s on line %d
 TestA::doSomething(2)
 int(1)
 
@@ -110,8 +108,6 @@ int(1)
 
 ===C===
 TestB::doSomethingParent(1)
-
-Strict Standards: call_user_func_array() expects parameter 1 to be a valid callback, non-static method TestA::doSomethingParent() should not be called statically, assuming $this from compatible context TestB in %s on line %d
 TestA::doSomethingParent(2)
 int(1)
 
index 1de77fb31b69d2b75c40622e813a145b2bee2b20..b50d8446d03683a8a50edf2e81a04391f006cfad 100644 (file)
@@ -37,8 +37,6 @@ object(foo)#%d (0) {
 
 Strict Standards: call_user_func() expects parameter 1 to be a valid callback, non-static method foo::test() should not be called statically in %s on line %d
 
-Strict Standards: Non-static method foo::test() should not be called statically in %s on line %d
-
 Strict Standards: Non-static method bar::show() should not be called statically in %s on line %d
 object(foo)#%d (0) {
 }
index cf624cb64b45a08ff05fbc9448d98bbc6947c47c..9137f3be7bd14e8557ea2c2746f2eb2c22291ec0 100644 (file)
@@ -2704,6 +2704,9 @@ static int zend_is_callable_check_class(zend_uchar utype, zstr name, int name_le
                } 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 (lcname_len == sizeof("parent") - 1 && 
@@ -2715,6 +2718,9 @@ static int zend_is_callable_check_class(zend_uchar utype, zstr name, int name_le
                } 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 (lcname_len == sizeof("static") - 1 &&
@@ -2724,10 +2730,23 @@ static int zend_is_callable_check_class(zend_uchar utype, zstr name, int name_le
                } 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_u_lookup_class(utype, name, name_len, &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) {
@@ -2749,9 +2768,9 @@ static int zend_is_callable_check_class(zend_uchar utype, zstr name, int name_le
 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;
+       int retval = 0;
        zstr lmname, mname, colon = NULL_ZSTR;
-       unsigned int clen = 0, mlen;
+       unsigned int clen = 0, lmlen, mlen;
        zend_class_entry *last_scope;
        HashTable *ftable;
        int call_via_handler = 0;
@@ -2769,24 +2788,24 @@ static int zend_is_callable_check_func(int check_flags, zval *callable, zend_fca
                        Z_USTRVAL_P(callable)[0] == ':' &&
                        Z_USTRVAL_P(callable)[1] == ':'
                ) {
-                       zstr tmp;
-
-                       tmp.u = Z_USTRVAL_P(callable) + 2;
-                       lmname = zend_u_str_case_fold(IS_UNICODE, tmp, Z_USTRLEN_P(callable)-2, 1, &mlen);
+                       mlen = Z_USTRLEN_P(callable) - 2;
+                       mname.u = Z_USTRVAL_P(callable) + 2;
+                       lmname = zend_u_str_case_fold(IS_UNICODE, mname, mlen, 1, &lmlen);
                } else if (Z_TYPE_P(callable) == IS_STRING &&
                        Z_STRVAL_P(callable)[0] == ':' &&
                        Z_STRVAL_P(callable)[1] == ':'
                ) {
-                       zstr tmp;
-
-                       tmp.s = Z_STRVAL_P(callable) + 2;
-                       lmname = zend_u_str_case_fold(IS_STRING, tmp, Z_STRLEN_P(callable)-2, 1, &mlen);
+                       mlen = Z_USTRLEN_P(callable) - 2;
+                       mname.u = Z_USTRVAL_P(callable) + 2;
+                       lmname = zend_u_str_case_fold(IS_STRING, mname, mlen, 1, &lmlen);
                } else {
-                       lmname = zend_u_str_case_fold(Z_TYPE_P(callable), Z_UNIVAL_P(callable), Z_UNILEN_P(callable), 1, &mlen);
+                       mlen = Z_UNILEN_P(callable);
+                       mname = Z_UNIVAL_P(callable);
+                       lmname = zend_u_str_case_fold(Z_TYPE_P(callable), Z_UNIVAL_P(callable), Z_UNILEN_P(callable), 1, &lmlen);
                }
                /* 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**)&fcc->function_handler) == SUCCESS) {
+               if (zend_u_hash_find(EG(function_table), Z_TYPE_P(callable), lmname, lmlen+1, (void**)&fcc->function_handler) == SUCCESS) {
                        efree(lmname.v);
                        return 1;
                }
@@ -2840,53 +2859,52 @@ static int zend_is_callable_check_func(int check_flags, zval *callable, zend_fca
                        if (error) zend_spprintf(error, 0, "class '%v' is not a subclass of '%v'", ce_org->name, fcc->calling_scope->name);
                        return 0;
                }
-               lmname = zend_u_str_case_fold(Z_TYPE_P(callable), mname, mlen, 1, &mlen);
        } 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);
+               mlen = Z_UNILEN_P(callable);
+               mname = Z_UNIVAL_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 '%Z' not found or invalid function name", callable);
+               if (error && !(check_flags & IS_CALLABLE_CHECK_SILENT)) {
+                       zend_spprintf(error, 0, "function '%Z' not found or invalid function name", callable);
+               }
                return 0;
        }
 
-       retval = zend_u_hash_find(ftable, Z_TYPE_P(callable), 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_u_str_case_fold(Z_TYPE_P(callable), mname, mlen, 1, &lmlen);
+       if (zend_u_hash_find(ftable, Z_TYPE_P(callable), lmname, lmlen+1, (void**)&fcc->function_handler) == SUCCESS) {
+               retval = 1;
+       } else if (fcc->object_pp && Z_OBJ_HT_PP(fcc->object_pp)->get_method) {
+               zstr method = mname;
+               int method_len = mlen;
+
+               if (UG(unicode) && Z_TYPE_P(callable) == IS_STRING) {
+                       zend_string_to_unicode(ZEND_U_CONVERTER(UG(runtime_encoding_conv)), &method.u, &method_len, mname.s, mlen TSRMLS_CC);
+               } else if (!UG(unicode) && Z_TYPE_P(callable) == IS_UNICODE) {
+                       zend_unicode_to_string(ZEND_U_CONVERTER(UG(runtime_encoding_conv)), &method.s, &method_len, mname.u, mlen TSRMLS_CC);
+               }       
+               fcc->function_handler = Z_OBJ_HT_PP(fcc->object_pp)->get_method(fcc->object_pp, method, method_len TSRMLS_CC);
+               if (method.v != mname.v) {
+                       efree(method.v);
+               }
+               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, Z_TYPE_P(callable), 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 '%v' does not have a method '%v'", fcc->calling_scope->name, lmname);
-                               } else {
-                                       if (error) zend_spprintf(error, 0, "function '%v' does not exist", lmname);
-                               }
-                       }
+                       fcc->function_handler = zend_std_get_static_method(fcc->calling_scope, Z_TYPE_P(callable), mname, mlen TSRMLS_CC);
                }
-       } else {
-               if (fcc->calling_scope) {
-                       if (!fcc->object_pp && !(fcc->function_handler->common.fn_flags & ZEND_ACC_STATIC)) {
+               retval = fcc->function_handler ? 1 : 0;
+               call_via_handler = 1;
+       }
+       efree(lmname.v);
+
+       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;
                                if (fcc->function_handler->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
@@ -2917,7 +2935,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);
@@ -2939,20 +2957,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 '%v' does not have a method '%R'", fcc->calling_scope->name, Z_TYPE_P(callable), mname);
+               } else {
+                       if (error) zend_spprintf(error, 0, "function '%R' does not exist", Z_TYPE_P(callable), mname);
+               }
        }
        if (fcc->object_pp) {
                fcc->called_scope = Z_OBJCE_PP(fcc->object_pp);
        }
-       efree(lmname.v);
-       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, zval *callable_name, 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, zval *callable_name, zend_fcall_info_cache *fcc, char **error TSRMLS_DC) /* {{{ */
 {
+       zend_bool ret;
        zend_fcall_info_cache fcc_local;
 
        if (callable_name) {
@@ -2975,16 +2999,71 @@ ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, zval *c
        switch (Z_TYPE_P(callable)) {
                case IS_STRING:
                case IS_UNICODE:
-                       if (callable_name) {
+                       if (object_pp && *object_pp) {
+                               fcc->object_pp = object_pp;
+                               fcc->calling_scope = Z_OBJCE_PP(object_pp);
+                               if (callable_name) {
+                                       if (UG(unicode)) {
+                                               Z_TYPE_P(callable_name) = IS_UNICODE;
+                                               Z_USTRLEN_P(callable_name) = fcc->calling_scope->name_length + Z_UNILEN_P(callable) + 2;
+                                               Z_USTRVAL_P(callable_name) = eumalloc(Z_USTRLEN_P(callable_name)+1);
+                                               memcpy(Z_USTRVAL_P(callable_name), fcc->calling_scope->name.u, UBYTES(fcc->calling_scope->name_length));
+                                               Z_USTRVAL_P(callable_name)[fcc->calling_scope->name_length] = ':';
+                                               Z_USTRVAL_P(callable_name)[fcc->calling_scope->name_length+1] = ':';
+                                               if (Z_TYPE_P(callable) == IS_UNICODE) {
+                                                       u_memcpy(Z_USTRVAL_P(callable_name)+fcc->calling_scope->name_length+2, Z_USTRVAL_P(callable), Z_USTRLEN_P(callable)+1);
+                                               } else {
+                                                       zval *method = callable;
+                                                       zval copy;
+                                                       int use_copy;
+
+                                                       zend_make_unicode_zval(method, &copy, &use_copy);
+                                                       u_memcpy(Z_USTRVAL_P(callable_name)+fcc->calling_scope->name_length+2, Z_USTRVAL(copy), Z_USTRLEN(copy)+1);
+                                                       zval_dtor(&copy);
+                                               }
+                                       } else {
+                                               Z_TYPE_P(callable_name) = IS_STRING;
+                                               Z_STRLEN_P(callable_name) = fcc->calling_scope->name_length + Z_UNILEN_P(callable) + 2;
+                                               Z_STRVAL_P(callable_name) = emalloc(Z_STRLEN_P(callable_name)+1);
+                                               memcpy(Z_STRVAL_P(callable_name), fcc->calling_scope->name.s, fcc->calling_scope->name_length);
+                                               Z_STRVAL_P(callable_name)[fcc->calling_scope->name_length] = ':';
+                                               Z_STRVAL_P(callable_name)[fcc->calling_scope->name_length+1] = ':';
+                                               if (Z_TYPE_P(callable) == IS_STRING) {
+                                                       memcpy(Z_STRVAL_P(callable_name)+fcc->calling_scope->name_length+2, Z_STRVAL_P(callable), Z_STRLEN_P(callable)+1);
+                                               } else {
+                                                       zval *method = callable;
+                                                       zval copy;
+                                                       int use_copy;
+
+                                                       zend_make_string_zval(method, &copy, &use_copy);
+                                                       memcpy(Z_STRVAL_P(callable_name)+fcc->calling_scope->name_length+2, Z_STRVAL(copy), Z_STRLEN(copy)+1);
+                                                       zval_dtor(&copy);
+                                               }
+                                       }
+                               }
+                       } else if (callable_name) {
                                *callable_name = *callable;
                                zval_copy_ctor(callable_name);
                                convert_to_text(callable_name);
                        }
                        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.v);
+                               }
+                               efree(fcc->function_handler);
+                       }
+                       return ret;
 
                case IS_ARRAY:
                        {
@@ -3113,7 +3192,20 @@ ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, zval *c
                                                }
                                        }
 
-                                       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.v);
+                                               }
+                                               efree(fcc->function_handler);
+                                       }
+                                       return ret;
+
                                } else {
                                        if (zend_hash_num_elements(Z_ARRVAL_P(callable)) == 2) {
                                                if (!obj || (Z_TYPE_PP(obj) != IS_OBJECT && Z_TYPE_PP(obj) != IS_STRING && Z_TYPE_PP(obj) != IS_UNICODE)) {
@@ -3171,7 +3263,7 @@ 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 TSRMLS_CC);
+       return zend_is_callable_ex(callable, NULL, check_flags, callable_name, NULL, NULL TSRMLS_CC);
 }
 /* }}} */
 
@@ -3179,7 +3271,7 @@ ZEND_API zend_bool zend_make_callable(zval *callable, zval *callable_name TSRMLS
 {
        zend_fcall_info_cache fcc;
 
-       if (zend_is_callable_ex(callable, IS_CALLABLE_STRICT, callable_name, &fcc, NULL TSRMLS_CC)) {
+       if (zend_is_callable_ex(callable, NULL, IS_CALLABLE_STRICT, callable_name, &fcc, NULL TSRMLS_CC)) {
                if ((Z_TYPE_P(callable) == IS_STRING ||
                     Z_TYPE_P(callable) == IS_UNICODE) &&
                    fcc.calling_scope) {
@@ -3189,6 +3281,16 @@ ZEND_API zend_bool zend_make_callable(zval *callable, zval *callable_name TSRMLS
                        add_next_index_text(callable, fcc.calling_scope->name, 1);
                        add_next_index_text(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.v);
+                       }
+                       efree(fcc.function_handler);
+               }
                return 1;
        }
        return 0;
@@ -3197,7 +3299,7 @@ ZEND_API zend_bool zend_make_callable(zval *callable, zval *callable_name TSRMLS
 
 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) /* {{{ */
 {
-       if (!zend_is_callable_ex(callable, check_flags, callable_name, fcc, error TSRMLS_CC)) {
+       if (!zend_is_callable_ex(callable, NULL, check_flags, callable_name, fcc, error TSRMLS_CC)) {
                return FAILURE;
        }
 
index 1403b9fa65e7b7d18b180aae6d47299b8dc7cfc3..df6b1198b721d94b4c61c38940eed6e992061d89 100644 (file)
@@ -280,10 +280,11 @@ ZEND_API void zend_wrong_param_count(TSRMLS_D);
 #define IS_CALLABLE_CHECK_SYNTAX_ONLY (1<<0)
 #define IS_CALLABLE_CHECK_NO_ACCESS   (1<<1)
 #define IS_CALLABLE_CHECK_IS_STATIC   (1<<2)
+#define IS_CALLABLE_CHECK_SILENT      (1<<3)
 
 #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_fcall_info_cache *fcc, char **error TSRMLS_DC);
+ZEND_API zend_bool zend_is_callable_ex(zval *callable, zval **object_pp, uint check_flags, zval *callable_name, zend_fcall_info_cache *fcc, 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);
index c64557f25abafed00d9a1ff05bd0a4883b02d331..1e70319d33ac1b3d94ada54053d6f2f906f7aafb 100644 (file)
@@ -36,7 +36,6 @@ typedef struct _zend_closure {
        zend_object    std;
        zend_function  func;
        zval          *this_ptr;
-       zend_function *invoke;
 } zend_closure;
 
 static zend_class_entry *zend_ce_closure;
@@ -44,6 +43,7 @@ static zend_object_handlers closure_handlers;
 
 ZEND_METHOD(Closure, __invoke) /* {{{ */
 {
+       zend_function *func = EG(current_execute_data)->function_state.function;
        zval ***arguments;
        zval *closure_result_ptr = NULL;
 
@@ -51,16 +51,10 @@ ZEND_METHOD(Closure, __invoke) /* {{{ */
        if (zend_get_parameters_array_ex(ZEND_NUM_ARGS(), arguments) == FAILURE) {
                efree(arguments);
                zend_error(E_ERROR, "Cannot get arguments for calling closure");
-               RETURN_FALSE;
-       }
-
-       if (call_user_function_ex(CG(function_table), NULL, this_ptr, &closure_result_ptr, ZEND_NUM_ARGS(), arguments, 1, NULL TSRMLS_CC) == FAILURE) {
-               efree(arguments);
-               RETURN_FALSE;
-       }
-
-       efree(arguments);
-       if (closure_result_ptr) {
+               RETVAL_FALSE;
+       } else if (call_user_function_ex(CG(function_table), NULL, this_ptr, &closure_result_ptr, ZEND_NUM_ARGS(), arguments, 1, NULL TSRMLS_CC) == FAILURE) {
+               RETVAL_FALSE;
+       } else if (closure_result_ptr) {
                if (Z_ISREF_P(closure_result_ptr) && return_value_ptr) {
                        if (return_value) {
                                zval_ptr_dtor(&return_value);
@@ -70,13 +64,12 @@ ZEND_METHOD(Closure, __invoke) /* {{{ */
                        RETVAL_ZVAL(closure_result_ptr, 1, 1);
                }
        }
-}
-/* }}} */
+       efree(arguments);
 
-const static zend_function_entry closure_functions[] = { /* {{{ */
-       ZEND_ME(Closure, __invoke, NULL, 0)
-       {NULL, NULL, NULL}
-};
+       /* destruct the function also, then - we have allocated it in get_method */
+       efree(func->internal_function.function_name.v);
+       efree(func);
+}
 /* }}} */
 
 static zend_function *zend_closure_get_constructor(zval *object TSRMLS_DC) /* {{{ */
@@ -128,22 +121,21 @@ static zend_function *zend_closure_get_method(zval **object_ptr, zstr method_nam
                (ZEND_U_EQUAL(type, lc_name, lc_name_len, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1))
        ) {
                zend_closure *closure = (zend_closure *)zend_object_store_get_object(*object_ptr TSRMLS_CC);
-
-               if (!closure->invoke) {
-                       closure->invoke = (zend_function*)emalloc(sizeof(zend_function));
-                       closure->invoke->common = closure->func.common;
-                       closure->invoke->type = ZEND_INTERNAL_FUNCTION;
-                       closure->invoke->internal_function.handler = ZEND_MN(Closure___invoke);
-                       closure->invoke->internal_function.module = 0;
-                       closure->invoke->internal_function.scope = zend_ce_closure;
-                       if (UG(unicode)) {
-                               closure->invoke->internal_function.function_name.u = USTR_MAKE(ZEND_INVOKE_FUNC_NAME);
-                       } else {
-                               closure->invoke->internal_function.function_name.s = ZEND_INVOKE_FUNC_NAME;
-                       }
+               zend_function *invoke = (zend_function*)emalloc(sizeof(zend_function));
+
+               invoke->common = closure->func.common;
+               invoke->type = ZEND_INTERNAL_FUNCTION;
+               invoke->internal_function.fn_flags = ZEND_ACC_CALL_VIA_HANDLER;
+               invoke->internal_function.handler = ZEND_MN(Closure___invoke);
+               invoke->internal_function.module = 0;
+               invoke->internal_function.scope = zend_ce_closure;
+               if (UG(unicode)) {
+                       invoke->internal_function.function_name.u = USTR_MAKE(ZEND_INVOKE_FUNC_NAME);
+               } else {
+                       invoke->internal_function.function_name.s = estrndup(ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1);
                }
                efree(lc_name.v);
-               return (zend_function *)closure->invoke;
+               return invoke;
        }
        efree(lc_name.v);
        return NULL;
@@ -204,13 +196,6 @@ static void zend_closure_free_storage(void *object TSRMLS_DC) /* {{{ */
                zval_ptr_dtor(&closure->this_ptr);
        }
 
-       if (closure->invoke) {
-               if (UG(unicode)) {
-                       efree(closure->invoke->internal_function.function_name.u);
-               }
-               efree(closure->invoke);
-       }
-
        efree(closure);
 }
 /* }}} */
@@ -236,7 +221,7 @@ void zend_register_closure_ce(TSRMLS_D) /* {{{ */
 {
        zend_class_entry ce;
 
-       INIT_CLASS_ENTRY(ce, "Closure", closure_functions);
+       INIT_CLASS_ENTRY(ce, "Closure", NULL);
        zend_ce_closure = zend_register_internal_class(&ce TSRMLS_CC);
        zend_ce_closure->ce_flags |= ZEND_ACC_FINAL_CLASS;
        zend_ce_closure->create_object = zend_closure_new;
index df64ee090fd009374e1e4635096105b72fe0989b..e2f09ccfda29fee6b3c4ec5f4c4fc8a0373678ee 100644 (file)
@@ -155,6 +155,8 @@ typedef struct _zend_try_catch_element {
 
 char *zend_visibility_string(zend_uint fn_flags);
 
+/* function flag for internal user call handlers __call, __callstatic */
+#define ZEND_ACC_CALL_VIA_HANDLER     0x200000
 
 typedef struct _zend_property_info {
        zend_uint flags;
index 6ca0e63def7e761dd792cf3549cd2c5377d7a802..0360b555b599cd19586e9559fccd4df2c743c711 100644 (file)
@@ -740,16 +740,9 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS
        zend_class_entry *current_called_scope;
        zend_class_entry *calling_scope = NULL;
        zend_class_entry *called_scope = NULL;
-       zend_class_entry *check_scope_or_static = NULL;
        zval *current_this;
        zend_execute_data execute_data;
-       zval *method_name;
-       zval *params_array;
-       int call_via_handler = 0;
        char *old_func_name = NULL;
-       unsigned int clen, lcname_len;
-       int fname_len;
-       zstr colon, fname, cname, lcname;
 
        *fci->retval_ptr_ptr = NULL;
 
@@ -784,304 +777,40 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS
        }
 
        if (!fci_cache || !fci_cache->initialized) {
-               if (Z_TYPE_P(fci->function_name) == IS_ARRAY) { /* assume array($obj, $name) couple */
-                       zval **tmp_object_ptr, **tmp_real_function_name;
-
-                       if (zend_hash_index_find(Z_ARRVAL_P(fci->function_name), 0, (void **) &tmp_object_ptr) == FAILURE) {
-                               return FAILURE;
-                       }
-                       if (zend_hash_index_find(Z_ARRVAL_P(fci->function_name), 1, (void **) &tmp_real_function_name) == FAILURE) {
-                               return FAILURE;
-                       }
-                       fci->function_name = *tmp_real_function_name;
-                       SEPARATE_ZVAL_IF_NOT_REF(tmp_object_ptr);
-                       fci->object_pp = tmp_object_ptr;
-                       Z_SET_ISREF_PP(fci->object_pp);
-               }
-
-               if (fci->object_pp && !*fci->object_pp) {
-                       fci->object_pp = NULL;
-               }
-
-               if (fci->object_pp) {
-                       if (Z_TYPE_PP(fci->object_pp) == IS_OBJECT
-                               && (!EG(objects_store).object_buckets || !EG(objects_store).object_buckets[Z_OBJ_HANDLE_PP(fci->object_pp)].valid)) {
-                               return FAILURE;
-                       }
-                       /* TBI!! new object handlers */
-                       if (Z_TYPE_PP(fci->object_pp) == IS_OBJECT) {
-                               if (!IS_ZEND_STD_OBJECT(**fci->object_pp)) {
-                                       zend_error(E_WARNING, "Cannot use call_user_function on objects without a class entry");
-                                       return FAILURE;
-                               }
-
-                               calling_scope = called_scope = Z_OBJCE_PP(fci->object_pp);
-                               fci->function_table = &calling_scope->function_table;
-                               EX(object) = *fci->object_pp;
-                       } else if (Z_TYPE_PP(fci->object_pp) == IS_STRING ||
-                               Z_TYPE_PP(fci->object_pp) == IS_UNICODE
-                       ) {
-                               zend_class_entry **ce;
-                               int found = FAILURE;
-
-                               if (Z_UNILEN_PP(fci->object_pp) == sizeof("self") - 1 &&
-                                       ZEND_U_EQUAL(Z_TYPE_PP(fci->object_pp), Z_UNIVAL_PP(fci->object_pp), Z_UNILEN_PP(fci->object_pp), "self", sizeof("self") - 1)
-                               ) {
-                                       if (!EG(active_op_array) || !EG(active_op_array)->scope) {
-                                               zend_error(E_ERROR, "Cannot access self:: when no class scope is active");
-                                       }
-                                       ce = &(EG(active_op_array)->scope);
-                                       found = (*ce != NULL?SUCCESS:FAILURE);
-                                       fci->object_pp = EG(This)?&EG(This):NULL;
-                                       EX(object) = EG(This);
-                                       calling_scope = *ce;
-                                       called_scope = EG(called_scope) ? EG(called_scope) : calling_scope;
-                               } else if (EG(active_op_array) &&
-                                       Z_UNILEN_PP(fci->object_pp) == sizeof("parent") - 1 &&
-                                       ZEND_U_EQUAL(Z_TYPE_PP(fci->object_pp), Z_UNIVAL_PP(fci->object_pp), Z_UNILEN_PP(fci->object_pp), "parent", sizeof("parent") - 1)
-                               ) {
-                                       if (!EG(active_op_array) || !EG(active_op_array)->scope) {
-                                               zend_error(E_ERROR, "Cannot access parent:: when no class scope is active");
-                                       }
-                                       if (!EG(active_op_array)->scope->parent) {
-                                               zend_error(E_ERROR, "Cannot access parent:: when current class scope has no parent");
-                                       }
-                                       ce = &(EG(active_op_array)->scope->parent);
-                                       found = (*ce != NULL?SUCCESS:FAILURE);
-                                       fci->object_pp = EG(This)?&EG(This):NULL;
-                                       EX(object) = EG(This);
-                                       calling_scope = *ce;
-                                       called_scope = EG(called_scope) ? EG(called_scope) : calling_scope;
-                               } else if (Z_UNILEN_PP(fci->object_pp) == sizeof("static") - 1 &&
-                                       ZEND_U_EQUAL(Z_TYPE_PP(fci->object_pp), Z_UNIVAL_PP(fci->object_pp), Z_UNILEN_PP(fci->object_pp), "static", sizeof("static") - 1)
-                               ) {
-                                       if (!EG(called_scope)) {
-                                               zend_error(E_ERROR, "Cannot access static:: when no class scope is active");
-                                       }
-                                       ce = &(EG(called_scope));
-                                       found = (EG(called_scope) != NULL?SUCCESS:FAILURE);
-                                       fci->object_pp = EG(This)?&EG(This):NULL;
-                                       EX(object) = EG(This);
-                                       calling_scope = called_scope = EG(called_scope);
-                               } else {
-                                       zend_class_entry *scope;
-                                       scope = EG(active_op_array) ? EG(active_op_array)->scope : NULL;
-
-                                       found = zend_u_lookup_class(Z_TYPE_PP(fci->object_pp), Z_UNIVAL_PP(fci->object_pp), Z_UNILEN_PP(fci->object_pp), &ce TSRMLS_CC);
-                                       if (found == FAILURE) {
-                                               zend_error(E_ERROR, "Class '%R' not found", Z_TYPE_PP(fci->object_pp), Z_UNIVAL_PP(fci->object_pp));
-                                       }
-                                       if (scope && EG(This) &&
-                                               instanceof_function(Z_OBJCE_P(EG(This)), scope TSRMLS_CC) &&
-                                               instanceof_function(scope, *ce TSRMLS_CC)) {
-                                               fci->object_pp = &EG(This);
-                                               EX(object) = EG(This);
-                                       } else {
-                                               fci->object_pp = NULL;
-                                       }
-                                       calling_scope = called_scope = *ce;
-                               }
-                               if (found == FAILURE)
-                                       return FAILURE;
-
-                               fci->function_table = &(*ce)->function_table;
-                       } else {
-                               zend_error(E_NOTICE, "Non-callable array passed to zend_call_function()");
-                               return FAILURE;
-                       }
-
-                       if (fci->function_table == NULL) {
-                               return FAILURE;
-                       }
-               }
-
-               if (Z_TYPE_P(fci->function_name) == IS_OBJECT) {
-                       if (zend_get_closure(fci->function_name, &calling_scope, &EX(function_state).function, NULL, &fci->object_pp TSRMLS_CC) == SUCCESS) {
-                               called_scope = calling_scope;
-                               goto init_fci_cache;
-                       }
-               } else if (Z_TYPE_P(fci->function_name) != IS_STRING &&
-                       Z_TYPE_P(fci->function_name) != IS_UNICODE
-               ) {
-                       return FAILURE;
-               }
-
-               if (UG(unicode) && Z_TYPE_P(fci->function_name) == IS_STRING) {
-                       old_func_name = Z_STRVAL_P(fci->function_name);
-
-                       Z_STRVAL_P(fci->function_name) = estrndup(Z_STRVAL_P(fci->function_name), Z_STRLEN_P(fci->function_name));
-                       convert_to_unicode(fci->function_name);
-               }
-
-               fname = Z_UNIVAL_P(fci->function_name);
-               fname_len = Z_UNILEN_P(fci->function_name);
-               if (Z_TYPE_P(fci->function_name) == IS_UNICODE) {
-                       if (fname.u[0] == ':' && fname.u[0] == ':') {
-                               fname.u += 2;
-                               fname_len -= 2;
-                       }
-               } else {
-                       if (fname.s[0] == ':' && fname.s[0] == ':') {
-                               fname.s += 2;
-                               fname_len -= 2;
-                       }
-               }
-               EX(function_state).function = NULL;
-               lcname = zend_u_str_case_fold(Z_TYPE_P(fci->function_name), fname, fname_len, 1, &lcname_len);
-
-               if (!fci->object_pp &&
-                       zend_u_hash_find(fci->function_table, Z_TYPE_P(fci->function_name), lcname, lcname_len + 1, (void **) &EX(function_state).function) == SUCCESS
-               ) {
-                       efree(lcname.v);
-               } else {
-                       efree(lcname.v);
-
-                       cname = fname;
-
-                       if (Z_TYPE_P(fci->function_name) == IS_UNICODE) {
-                               if ((colon.u = u_memrchr(fname.u, ':', fname_len)) != NULL &&
-                                       colon.u > fname.u &&
-                                       *(colon.u - 1) == ':'
-                               ) {
-                                       clen = colon.u - fname.u - 1;
-                                       fname_len -= (clen + 2);
-                                       fname.u = colon.u + 1;
-                               } else {
-                                       colon.u = NULL;
-                               }
-                       } else {
-                               if ((colon.s = zend_memrchr(fname.s, ':', fname_len)) != NULL &&
-                                       colon.s > fname.s &&
-                                       *(colon.s - 1) == ':'
-                               ) {
-                                       clen = colon.s - fname.s - 1;
-                                       fname_len -= (clen + 2);
-                                       fname.s = colon.s + 1;
-                               } else {
-                                       colon.s = NULL;
-                               }
-                       }
-                       if (colon.v != NULL) {
-                               zend_class_entry **pce, *ce_child = NULL;
-
-                               lcname = zend_u_str_case_fold(Z_TYPE_P(fci->function_name), cname, clen, 1, &clen);
-                               /* caution: lcname is not '\0' terminated */
-                               if (clen == sizeof("self") - 1 &&
-                                       ZEND_U_EQUAL(Z_TYPE_P(fci->function_name), lcname, clen, "self", sizeof("self") - 1)
-                               ) {
-                                       if (!EG(active_op_array) || !EG(active_op_array)->scope) {
-                                               zend_error(E_ERROR, "Cannot access self:: when no class scope is active");
-                                       }
-                                       ce_child = EG(active_op_array) ? EG(active_op_array)->scope : NULL;
-                                       called_scope = EG(called_scope) ? EG(called_scope) : ce_child;
-                               } else if (clen == sizeof("parent") - 1 &&
-                                       ZEND_U_EQUAL(Z_TYPE_P(fci->function_name), lcname, clen, "parent", sizeof("parent") - 1)
-                               ) {
-                                       if (!EG(active_op_array) || !EG(active_op_array)->scope) {
-                                               zend_error(E_ERROR, "Cannot access parent:: when no class scope is active");
-                                       }
-                                       if (!EG(active_op_array)->scope->parent) {
-                                               zend_error(E_ERROR, "Cannot access parent:: when current class scope has no parent");
-                                       }
-                                       ce_child = EG(active_op_array) && EG(active_op_array)->scope ? EG(active_op_array)->scope->parent : NULL;
-                                       called_scope = EG(called_scope) ? EG(called_scope) : ce_child;
-                               } else if (clen == sizeof("static") - 1 &&
-                                       ZEND_U_EQUAL(Z_TYPE_P(fci->function_name), lcname, clen, "static", sizeof("static") - 1)
-                               ) {
-                                       if (!EG(called_scope)) {
-                                               zend_error(E_ERROR, "Cannot access static:: when no class scope is active");
-                                       }
-                                       called_scope = ce_child = EG(called_scope);
-                               } else if (zend_u_lookup_class_ex(Z_TYPE_P(fci->function_name), lcname, clen, cname, 0, &pce TSRMLS_CC) == SUCCESS) {
-                                       called_scope = ce_child = *pce;
-                               }
-                               efree(lcname.v);
-
-                               if (!ce_child) {
-                                       zend_error(E_ERROR, "Cannot call method %R() or method does not exist", Z_TYPE_P(fci->function_name), Z_UNIVAL_P(fci->function_name));
-                                       return FAILURE;
-                               }
-                               check_scope_or_static = calling_scope;
-                               fci->function_table = &ce_child->function_table;
-                               calling_scope = ce_child;
-                       }
-
-                       if (fci->object_pp) {
-                               if (Z_OBJ_HT_PP(fci->object_pp)->get_method == NULL) {
-                                       zend_error(E_ERROR, "Object does not support method calls");
-                               }
-                               EX(function_state).function =
-                                       Z_OBJ_HT_PP(fci->object_pp)->get_method(fci->object_pp, fname, fname_len TSRMLS_CC);
-                               if (EX(function_state).function && calling_scope != EX(function_state).function->common.scope) {
-                                       zstr function_name_lc = zend_u_str_tolower_dup(Z_TYPE_P(fci->function_name), fname, fname_len);
-                                       if (zend_u_hash_find(&calling_scope->function_table, Z_TYPE_P(fci->function_name), function_name_lc, fname_len + 1, (void **) &EX(function_state).function) == FAILURE) {
-                                               efree(function_name_lc.v);
-                                               zend_error(E_ERROR, "Cannot call method %v::%R() or method does not exist", calling_scope->name, Z_TYPE_P(fci->function_name), fname);
-                                       }
-                                       efree(function_name_lc.v);
-                               }
-                       } else if (calling_scope) {
-                               if (calling_scope->get_static_method) {
-                                       EX(function_state).function = calling_scope->get_static_method(calling_scope, Z_TYPE_P(fci->function_name), fname, fname_len TSRMLS_CC);
-                               } else {
-                                       EX(function_state).function = zend_std_get_static_method(calling_scope, Z_TYPE_P(fci->function_name), fname, fname_len TSRMLS_CC);
-                               }
-                               
-                               if (((zend_internal_function*)EX(function_state).function)->handler == zend_std_call_user_call)  {
-                                       fci->object_pp = &EG(This);
-                               }
-
-                               if (check_scope_or_static && EX(function_state).function
-                               && !(EX(function_state).function->common.fn_flags & ZEND_ACC_STATIC)
-                               && !instanceof_function(check_scope_or_static, calling_scope TSRMLS_CC)) {
-                                       zend_error(E_ERROR, "Cannot call method %R() of class %v which is not a derived from %v", Z_TYPE_P(fci->function_name), Z_UNIVAL_P(fci->function_name), calling_scope->name, check_scope_or_static->name);
-                                       return FAILURE;
-                               }
-                       }
-               }
-
-               if (EX(function_state).function == NULL) {
-                       /* try calling __call */
-                       if (calling_scope && calling_scope->__call) {
-                               EX(function_state).function = calling_scope->__call;
-                               /* prepare params */
-                               ALLOC_INIT_ZVAL(method_name);
-                               ZVAL_STRINGL(method_name, fname.s, fname_len, 0);
-
-                               ALLOC_INIT_ZVAL(params_array);
-                               array_init(params_array);
-                               call_via_handler = 1;
-                       } else {
-                               if (old_func_name) {
-                                       efree(Z_STRVAL_P(fci->function_name));
-                                       Z_TYPE_P(fci->function_name) = IS_STRING;
-                                       Z_STRVAL_P(fci->function_name) = old_func_name;
-                               }
-                               return FAILURE;
-                       }
-               }
-
-init_fci_cache:
-               if (fci_cache &&
-                       (EX(function_state).function->type != ZEND_INTERNAL_FUNCTION ||
-                       ((zend_internal_function*)EX(function_state).function)->handler != zend_std_call_user_call)
-               ) {
-                       fci_cache->function_handler = EX(function_state).function;
-                       fci_cache->object_pp = fci->object_pp;
-                       fci_cache->calling_scope = calling_scope;
-                       fci_cache->called_scope = called_scope;
-                       fci_cache->initialized = 1;
-               }
-       } else {
-               EX(function_state).function = fci_cache->function_handler;
-               calling_scope = fci_cache->calling_scope;
-               called_scope = fci_cache->called_scope;
-               fci->object_pp = fci_cache->object_pp;
-               EX(object) = fci->object_pp ? *fci->object_pp : NULL;
-               if (fci->object_pp && *fci->object_pp && Z_TYPE_PP(fci->object_pp) == IS_OBJECT
-                       && (!EG(objects_store).object_buckets || !EG(objects_store).object_buckets[Z_OBJ_HANDLE_PP(fci->object_pp)].valid)) {
-                       return FAILURE;
-               }
+               zend_fcall_info_cache fci_cache_local;
+               zval callable_name;
+               char *error = NULL;
+
+               if (!fci_cache) {
+                       fci_cache = &fci_cache_local;
+               }
+
+               if (!zend_is_callable_ex(fci->function_name, fci->object_pp, IS_CALLABLE_CHECK_SILENT, &callable_name, fci_cache, &error TSRMLS_CC)) {
+                       if (error) {
+                               zend_error(E_WARNING, "Invalid callback %Z, %s", callable_name, error);
+                               efree(error);
+                       }
+                       zval_dtor(&callable_name);
+                       return FAILURE;
+               } else if (error) {
+                       /* Capitalize the first latter of the error message */
+                       if (error[0] >= 'a' && error[0] <= 'z') {
+                               error[0] += ('A' - 'a');
+                       }
+                       zend_error(E_STRICT, "%s", error);
+                       efree(error);
+               }
+               zval_dtor(&callable_name);
+       }
+
+       EX(function_state).function = fci_cache->function_handler;
+       calling_scope = fci_cache->calling_scope;
+       called_scope = fci_cache->called_scope;
+       fci->object_pp = fci_cache->object_pp;
+       EX(object) = fci->object_pp ? *fci->object_pp : NULL;
+       if (fci->object_pp && *fci->object_pp && Z_TYPE_PP(fci->object_pp) == IS_OBJECT
+               && (!EG(objects_store).object_buckets || !EG(objects_store).object_buckets[Z_OBJ_HANDLE_PP(fci->object_pp)].valid)) {
+               return FAILURE;
        }
 
        if (EX(function_state).function->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) {
@@ -1096,11 +825,7 @@ init_fci_cache:
                }
        }
 
-       if (call_via_handler) {
-               ZEND_VM_STACK_GROW_IF_NEEDED(2 + 1);
-       } else {
-               ZEND_VM_STACK_GROW_IF_NEEDED(fci->param_count + 1);
-       }
+       ZEND_VM_STACK_GROW_IF_NEEDED(fci->param_count + 1);
 
        for (i=0; i<fci->param_count; i++) {
                zval *param;
@@ -1122,10 +847,6 @@ init_fci_cache:
                                                Z_STRVAL_P(fci->function_name) = old_func_name;
                                        }
 
-                                       if (call_via_handler) {
-                                               zval_ptr_dtor(&method_name);
-                                               zval_ptr_dtor(&params_array);
-                                       }
                                        zend_error(E_WARNING, "Parameter %d to %v%s%v() expected to be a reference, value given",
                                                i+1,
                                                EX(function_state).function->common.scope ? EX(function_state).function->common.scope->name : EMPTY_ZSTR,
@@ -1151,17 +872,7 @@ init_fci_cache:
                        *param = **(fci->params[i]);
                        INIT_PZVAL(param);
                }
-               if (call_via_handler) {
-                       add_next_index_zval(params_array, param);
-               } else {
-                       zend_vm_stack_push_nocheck(param TSRMLS_CC);
-               }
-       }
-
-       if (call_via_handler) {
-               zend_vm_stack_push_nocheck(method_name TSRMLS_CC);
-               zend_vm_stack_push_nocheck(params_array TSRMLS_CC);
-               fci->param_count = 2;
+               zend_vm_stack_push_nocheck(param TSRMLS_CC);
        }
 
        EX(function_state).arguments = zend_vm_stack_top(TSRMLS_C);
@@ -1199,19 +910,6 @@ init_fci_cache:
                }
        } else {
                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 {
-                               /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */
-                               severity = E_ERROR;
-                               verb = "cannot";
-                       }
-                       zend_error(severity, "Non-static method %v::%v() %s be called statically", calling_scope->name, EX(function_state).function->common.function_name, verb);
-               }
        }
 
        EX(prev_execute_data) = EG(current_execute_data);
@@ -1248,6 +946,8 @@ init_fci_cache:
                EG(return_value_ptr_ptr)=original_return_value;
                EG(opline_ptr) = original_opline_ptr;
        } else {
+               int call_via_handler = (EX(function_state).function->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0;
+
                ALLOC_INIT_ZVAL(*fci->retval_ptr_ptr);
                if (EX(function_state).function->common.scope) {
                        EG(scope) = EX(function_state).function->common.scope;
@@ -1263,12 +963,13 @@ init_fci_cache:
                        zval_ptr_dtor(fci->retval_ptr_ptr);
                        *fci->retval_ptr_ptr = NULL;
                }
+
+               if (call_via_handler) {
+                       /* We must re-initialize function again */
+                       fci_cache->initialized = 0;
+               }
        }
        zend_vm_stack_clear_multiple(TSRMLS_C);
-       if (call_via_handler) {
-               zval_ptr_dtor(&method_name);
-               zval_ptr_dtor(&params_array);
-       }
 
        if (EG(This)) {
                zval_ptr_dtor(&EG(This));
index 4e2d7e1d44cba0f58c2d5a5061ff2b50f6a68338..7f3486683f31984a8daaa4d5b8e360cc7b628ca0 100644 (file)
@@ -803,7 +803,7 @@ static union _zend_function *zend_std_get_method(zval **object_ptr, zstr method_
                        call_user_call->arg_info = NULL;
                        call_user_call->num_args = 0;
                        call_user_call->scope = zobj->ce;
-                       call_user_call->fn_flags = 0;
+                       call_user_call->fn_flags = ZEND_ACC_CALL_VIA_HANDLER;
                        if (UG(unicode)) {
                                call_user_call->function_name.u = eustrndup(method_name.u, method_len);
                        } else {
@@ -939,7 +939,7 @@ ZEND_API zend_function *zend_std_get_static_method(zend_class_entry *ce, zend_uc
                        call_user_call->arg_info = NULL;
                        call_user_call->num_args = 0;
                        call_user_call->scope = ce;
-                       call_user_call->fn_flags = 0;
+                       call_user_call->fn_flags = ZEND_ACC_CALL_VIA_HANDLER;
                        if (UG(unicode)) {
                                call_user_call->function_name.u = eustrndup(function_name_strval.u, function_name_strlen);
                        } else {
@@ -957,7 +957,7 @@ ZEND_API zend_function *zend_std_get_static_method(zend_class_entry *ce, zend_uc
                        callstatic_user_call->arg_info = NULL;
                        callstatic_user_call->num_args = 0;
                        callstatic_user_call->scope    = ce;
-                       callstatic_user_call->fn_flags = ZEND_ACC_STATIC | ZEND_ACC_PUBLIC;
+                       callstatic_user_call->fn_flags = ZEND_ACC_STATIC | ZEND_ACC_PUBLIC | ZEND_ACC_CALL_VIA_HANDLER;
 
                        if (UG(unicode)) {
                                callstatic_user_call->function_name.u = eustrndup(function_name_strval.u, function_name_strlen);
@@ -970,12 +970,7 @@ ZEND_API zend_function *zend_std_get_static_method(zend_class_entry *ce, zend_uc
 
                        return (zend_function *)callstatic_user_call;
                } else {
-                       zstr class_name = ce->name;
-
-                       if (!class_name.v) {
-                               class_name.u = EMPTY_STR;
-                       }
-                       zend_error(E_ERROR, "Call to undefined method %R::%R()", type, class_name, type, function_name_strval);
+                       return NULL;
                }
        }
        efree(lc_function_name.v);
index 4a70eeda9b66341f1ac1200778f5e57609d0b6a8..d670342cc819cdf2bae6e0512c43116da57bdeb5 100644 (file)
@@ -2035,6 +2035,9 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMP|VAR|UNUS
                        } else {
                                EX(fbc) = zend_std_get_static_method(ce, function_name_type, function_name_strval, function_name_strlen TSRMLS_CC);
                        }
+                       if (!EX(fbc)) {
+                               zend_error(E_ERROR, "Call to undefined method %v::%R()", ce->name, function_name_type, function_name_strval);
+                       }
                }
 
                if (OP2_TYPE != IS_CONST) {
index 874ac129ef9ff295bfb9c76ee9bf67c581a0807f..f5c5e6673dc84dd2f5b4c124106ed14958210e14 100644 (file)
@@ -2721,6 +2721,9 @@ static int ZEND_FASTCALL  ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CONST_HANDLER(
                        } else {
                                EX(fbc) = zend_std_get_static_method(ce, function_name_type, function_name_strval, function_name_strlen TSRMLS_CC);
                        }
+                       if (!EX(fbc)) {
+                               zend_error(E_ERROR, "Call to undefined method %v::%R()", ce->name, function_name_type, function_name_strval);
+                       }
                }
 
                if (IS_CONST != IS_CONST) {
@@ -3322,6 +3325,9 @@ static int ZEND_FASTCALL  ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_TMP_HANDLER(ZE
                        } else {
                                EX(fbc) = zend_std_get_static_method(ce, function_name_type, function_name_strval, function_name_strlen TSRMLS_CC);
                        }
+                       if (!EX(fbc)) {
+                               zend_error(E_ERROR, "Call to undefined method %v::%R()", ce->name, function_name_type, function_name_strval);
+                       }
                }
 
                if (IS_TMP_VAR != IS_CONST) {
@@ -3799,6 +3805,9 @@ static int ZEND_FASTCALL  ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_VAR_HANDLER(ZE
                        } else {
                                EX(fbc) = zend_std_get_static_method(ce, function_name_type, function_name_strval, function_name_strlen TSRMLS_CC);
                        }
+                       if (!EX(fbc)) {
+                               zend_error(E_ERROR, "Call to undefined method %v::%R()", ce->name, function_name_type, function_name_strval);
+                       }
                }
 
                if (IS_VAR != IS_CONST) {
@@ -4032,6 +4041,9 @@ static int ZEND_FASTCALL  ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_UNUSED_HANDLER
                        } else {
                                EX(fbc) = zend_std_get_static_method(ce, function_name_type, function_name_strval, function_name_strlen TSRMLS_CC);
                        }
+                       if (!EX(fbc)) {
+                               zend_error(E_ERROR, "Call to undefined method %v::%R()", ce->name, function_name_type, function_name_strval);
+                       }
                }
 
                if (IS_UNUSED != IS_CONST) {
@@ -4477,6 +4489,9 @@ static int ZEND_FASTCALL  ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CV_HANDLER(ZEN
                        } else {
                                EX(fbc) = zend_std_get_static_method(ce, function_name_type, function_name_strval, function_name_strlen TSRMLS_CC);
                        }
+                       if (!EX(fbc)) {
+                               zend_error(E_ERROR, "Call to undefined method %v::%R()", ce->name, function_name_type, function_name_strval);
+                       }
                }
 
                if (IS_CV != IS_CONST) {
@@ -10720,6 +10735,9 @@ static int ZEND_FASTCALL  ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZE
                        } else {
                                EX(fbc) = zend_std_get_static_method(ce, function_name_type, function_name_strval, function_name_strlen TSRMLS_CC);
                        }
+                       if (!EX(fbc)) {
+                               zend_error(E_ERROR, "Call to undefined method %v::%R()", ce->name, function_name_type, function_name_strval);
+                       }
                }
 
                if (IS_CONST != IS_CONST) {
@@ -12616,6 +12634,9 @@ static int ZEND_FASTCALL  ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND
                        } else {
                                EX(fbc) = zend_std_get_static_method(ce, function_name_type, function_name_strval, function_name_strlen TSRMLS_CC);
                        }
+                       if (!EX(fbc)) {
+                               zend_error(E_ERROR, "Call to undefined method %v::%R()", ce->name, function_name_type, function_name_strval);
+                       }
                }
 
                if (IS_TMP_VAR != IS_CONST) {
@@ -14488,6 +14509,9 @@ static int ZEND_FASTCALL  ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND
                        } else {
                                EX(fbc) = zend_std_get_static_method(ce, function_name_type, function_name_strval, function_name_strlen TSRMLS_CC);
                        }
+                       if (!EX(fbc)) {
+                               zend_error(E_ERROR, "Call to undefined method %v::%R()", ce->name, function_name_type, function_name_strval);
+                       }
                }
 
                if (IS_VAR != IS_CONST) {
@@ -15452,6 +15476,9 @@ static int ZEND_FASTCALL  ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_UNUSED_HANDLER(Z
                        } else {
                                EX(fbc) = zend_std_get_static_method(ce, function_name_type, function_name_strval, function_name_strlen TSRMLS_CC);
                        }
+                       if (!EX(fbc)) {
+                               zend_error(E_ERROR, "Call to undefined method %v::%R()", ce->name, function_name_type, function_name_strval);
+                       }
                }
 
                if (IS_UNUSED != IS_CONST) {
@@ -16974,6 +17001,9 @@ static int ZEND_FASTCALL  ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_
                        } else {
                                EX(fbc) = zend_std_get_static_method(ce, function_name_type, function_name_strval, function_name_strlen TSRMLS_CC);
                        }
+                       if (!EX(fbc)) {
+                               zend_error(E_ERROR, "Call to undefined method %v::%R()", ce->name, function_name_type, function_name_strval);
+                       }
                }
 
                if (IS_CV != IS_CONST) {
index d38fe6602494a716ceb0f74be37cb79f64032cb5..7234a7ef12c7005fc853152ce7ce50e193b8859b 100644 (file)
@@ -1279,7 +1279,7 @@ static void _reflection_export(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *c
        params[0] = &reflector_ptr;
        params[1] = &output_ptr;
 
-       ZVAL_ASCII_STRINGL(&fname, "export", sizeof("export") - 1, 1);
+       ZVAL_ASCII_STRINGL(&fname, "reflection::export", sizeof("reflection::export") - 1, 1);
        fci.function_table = &reflection_ptr->function_table;
        fci.function_name = &fname;
        fci.object_pp = NULL;
index ebacf6db682595fd6309ee156d92a243db419234..f8fa3a5a60fa0ee0a69c6ab87f957af1526e5863 100755 (executable)
@@ -453,7 +453,7 @@ PHP_FUNCTION(spl_autoload_register)
                        zval_dtor(&ztmp);
                }
        
-               if (!zend_is_callable_ex(zcallable, IS_CALLABLE_STRICT, &zfunc_name, &fcc, &error TSRMLS_CC)) {
+               if (!zend_is_callable_ex(zcallable, NULL, IS_CALLABLE_STRICT, &zfunc_name, &fcc, &error TSRMLS_CC)) {
                        alfi.ce = fcc.calling_scope;
                        alfi.func_ptr = fcc.function_handler;
                        obj_ptr = fcc.object_pp;
@@ -583,7 +583,7 @@ PHP_FUNCTION(spl_autoload_unregister)
                return;
        }
 
-       if (!zend_is_callable_ex(zcallable, IS_CALLABLE_CHECK_SYNTAX_ONLY, &zfunc_name, &fcc, &error TSRMLS_CC)) {
+       if (!zend_is_callable_ex(zcallable, NULL, IS_CALLABLE_CHECK_SYNTAX_ONLY, &zfunc_name, &fcc, &error TSRMLS_CC)) {
                zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Unable to unregister invalid function (%s)", error);
                if (error) {
                        efree(error);
index 3b6b3b90c11ce863cb7e3453453da6089a0089bf..3852578cf93d6a0d672ee934db74476feb725d03 100755 (executable)
@@ -57,7 +57,7 @@ foreach($funcs as $idx => $func)
 <?php exit(0); ?>
 --EXPECTF--
 unicode(22) "MyAutoLoader::notExist"
-Function 'MyAutoLoader::notExist' not found (class 'MyAutoLoader' does not have a method 'notexist')
+Function 'MyAutoLoader::notExist' not found (class 'MyAutoLoader' does not have a method 'notExist')
 
 unicode(22) "MyAutoLoader::noAccess"
 Function 'MyAutoLoader::noAccess' not callable (cannot access protected method MyAutoLoader::noAccess())
@@ -74,7 +74,7 @@ array(2) {
   [1]=>
   unicode(8) "notExist"
 }
-Passed array does not specify an existing static method (class 'MyAutoLoader' does not have a method 'notexist')
+Passed array does not specify an existing static method (class 'MyAutoLoader' does not have a method 'notExist')
 
 array(2) {
   [0]=>
@@ -107,7 +107,7 @@ array(2) {
   [1]=>
   unicode(8) "notExist"
 }
-Passed array does not specify an existing method (class 'MyAutoLoader' does not have a method 'notexist')
+Passed array does not specify an existing method (class 'MyAutoLoader' does not have a method 'notExist')
 
 array(2) {
   [0]=>
index 64b91fbec9c6102ae24f3ed6063956a2f3b1fe78..6565c3fee9dabf914725e897368920ac0b2eabfa 100644 (file)
@@ -70,7 +70,7 @@ class ChildClass extends AbstractClass
 {
   private $var3;
   public function emptyFunction() {
-    echo "defined in child";
+    echo "defined in child\n";
   }
 }
 test(array('ChildClass', 'emptyFunction'), array(1, 2));
@@ -80,7 +80,7 @@ class FinalClass
 {
   private $var4;
   final function finalMethod() {
-    echo "This function can't be overloaded";
+    echo "This function can't be overloaded\n";
   }
 }
 test(array('FinalClass', 'finalMethod'), array(1, 2));
@@ -128,10 +128,6 @@ test(array('InterClass', 'square'), array(1, 2));
 SimpleClass::square
 
 Strict Standards: array_map() expects parameter 1 to be a valid callback, non-static method SimpleClass::square() should not be called statically in %sarray_map_object1.php on line %d
-
-Strict Standards: Non-static method SimpleClass::square() should not be called statically in %sarray_map_object1.php on line %d
-
-Strict Standards: Non-static method SimpleClass::square() should not be called statically in %sarray_map_object1.php on line %d
 array(2) {
   [0]=>
   int(1)
@@ -161,11 +157,9 @@ NULL
 ChildClass::emptyFunction
 
 Strict Standards: array_map() expects parameter 1 to be a valid callback, non-static method ChildClass::emptyFunction() should not be called statically in %sarray_map_object1.php on line %d
-
-Strict Standards: Non-static method ChildClass::emptyFunction() should not be called statically in %sarray_map_object1.php on line %d
 defined in child
-Strict Standards: Non-static method ChildClass::emptyFunction() should not be called statically in %sarray_map_object1.php on line %d
-defined in childarray(2) {
+defined in child
+array(2) {
   [0]=>
   NULL
   [1]=>
@@ -176,11 +170,9 @@ defined in childarray(2) {
 FinalClass::finalMethod
 
 Strict Standards: array_map() expects parameter 1 to be a valid callback, non-static method FinalClass::finalMethod() should not be called statically in %sarray_map_object1.php on line %d
-
-Strict Standards: Non-static method FinalClass::finalMethod() should not be called statically in %sarray_map_object1.php on line %d
 This function can't be overloaded
-Strict Standards: Non-static method FinalClass::finalMethod() should not be called statically in %sarray_map_object1.php on line %d
-This function can't be overloadedarray(2) {
+This function can't be overloaded
+array(2) {
   [0]=>
   NULL
   [1]=>
index d1a6d8062955da7694941b985fe9818db28f2a3a..9424c441104942120fc0f25a4e8a489d5a131632 100644 (file)
@@ -74,7 +74,7 @@ array(3) {
 }
 -- accessing child method from parent class --
 
-Warning: array_map() expects parameter 1 to be a valid callback, class 'ParentClass' does not have a method 'staticchild' in %s on line %d
+Warning: array_map() expects parameter 1 to be a valid callback, class 'ParentClass' does not have a method 'staticChild' in %s on line %d
 NULL
 -- accessing parent method using child class object --
 array(3) {
@@ -87,6 +87,6 @@ array(3) {
 }
 -- accessing child method using parent class object --
 
-Warning: array_map() expects parameter 1 to be a valid callback, class 'ParentClass' does not have a method 'staticchild' in %s on line %d
+Warning: array_map() expects parameter 1 to be a valid callback, class 'ParentClass' does not have a method 'staticChild' in %s on line %d
 NULL
 Done
index c63fcfd0c82d82945caaba165dd5129dacbd8c51..11fdde2c51a0441032bd2790de107de16c691ec0 100755 (executable)
@@ -77,16 +77,8 @@ new Derived_6('6');
 --EXPECTF--
 Base::__construct(1)
 Base::__construct(2)
-
-Strict Standards: call_user_func_array() expects parameter 1 to be a valid callback, non-static method Base::__construct() cannot be called statically, assuming $this from compatible context Derived_3 in %s on line %d
 Base::__construct(3)
-
-Strict Standards: call_user_func_array() expects parameter 1 to be a valid callback, non-static method Base::__construct() cannot be called statically, assuming $this from compatible context Derived_4 in %s on line %d
 Base::__construct(4)
-
-Strict Standards: call_user_func_array() expects parameter 1 to be a valid callback, non-static method Base::__construct() cannot be called statically, assuming $this from compatible context Derived_5 in %s on line %d
 Base::__construct(5)
-
-Strict Standards: call_user_func_array() expects parameter 1 to be a valid callback, non-static method Base::__construct() cannot be called statically, assuming $this from compatible context Derived_6 in %s on line %d
 Base::__construct(6)
 ===DONE===
index 852bb46ecf77045fe846d8a71ca17345b5afaa74..a58f19d932b8e32ae27da790445437d34e1bd2f7 100644 (file)
@@ -97,12 +97,8 @@ B|who2
 A
 ===FOREIGN===
 parent|who
-
-Strict Standards: call_user_func() expects parameter 1 to be a valid callback, non-static method O::who() should not be called statically, assuming $this from compatible context P in %s on line %d
 O
 P|parent::who
-
-Strict Standards: call_user_func() expects parameter 1 to be a valid callback, non-static method O::who() should not be called statically, assuming $this from compatible context P in %s on line %d
 O
 $this|O::who
 O