cvs: ZendEngine2(PHP_5_3) / zend_API.c zend_API.h php-src/ext/standard type.c

[email protected] ("Marcus Boerger")
Newsgroups php.doc,php.zend-engine.cvs
Message-ID <cvshelly1201901275@cvsserver>
helly		Fri Feb  1 21:27:55 2008 UTC

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