php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login

Patch ReflectionMethod-invoke-static-bindings for Reflection related Bug #62113

Patch version 2012-05-22 21:38 UTC

Return to Bug #62113 | Download this patch
Patch Revisions:

Developer: nathanbruer@gmail.com

 ext/reflection/php_reflection.c |  105 ++++++++++++++++++++++++++++++++-------
 1 file changed, 87 insertions(+), 18 deletions(-)

diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c
index 406da93..858a0f2 100644
--- a/ext/reflection/php_reflection.c
+++ b/ext/reflection/php_reflection.c
@@ -2807,7 +2807,7 @@ ZEND_METHOD(reflection_method, invoke)
 	int result, num_args = 0;
 	zend_fcall_info fci;
 	zend_fcall_info_cache fcc;
-	zend_class_entry *obj_ce;
+	zend_class_entry *obj_ce, **ce_p;
 
 	METHOD_NOTSTATIC(reflection_method_ptr);
 
@@ -2842,8 +2842,42 @@ ZEND_METHOD(reflection_method, invoke)
 	 * Else, we verify that the given object is an instance of the class.
 	 */
 	if (mptr->common.fn_flags & ZEND_ACC_STATIC) {
+		object_ptr = *params[0];
+		if (IS_ZEND_STD_OBJECT(*object_ptr)) {
+			obj_ce = Z_OBJCE_P(object_ptr);
+		} else if (Z_TYPE_P(object_ptr) == IS_NULL) {
+			obj_ce = mptr->common.scope;
+		} else {
+			char *class_name;
+			int class_name_len;
+			zval tmp_zval;
+			INIT_ZVAL(tmp_zval);
+
+			if (Z_TYPE_P(object_ptr) == IS_STRING) {
+				class_name = Z_STRVAL_P(object_ptr);
+				class_name_len = Z_STRLEN_P(object_ptr);
+			} else {
+				tmp_zval = *object_ptr;
+				zval_copy_ctor(&tmp_zval);
+				convert_to_string(&tmp_zval);
+				class_name = Z_STRVAL(tmp_zval);
+				class_name_len = Z_STRLEN(tmp_zval);
+			}
+
+			if ((class_name_len == sizeof("static") - 1) &&
+				(memcmp("static", class_name, sizeof("static") - 1) == 0)) {
+				obj_ce = mptr->common.scope;
+			}
+			else if (zend_lookup_class_ex(class_name, class_name_len, NULL, 1, &ce_p TSRMLS_CC) == FAILURE) {
+				zend_error(E_WARNING, "Class '%s' not found", class_name);
+				zval_dtor(&tmp_zval);
+				RETURN_NULL();
+			} else {
+				obj_ce = *ce_p;
+			}
+			zval_dtor(&tmp_zval);
+		}
 		object_ptr = NULL;
-		obj_ce = mptr->common.scope;
 	} else {
 		if (Z_TYPE_PP(params[0]) != IS_OBJECT) {
 			efree(params);
@@ -2853,13 +2887,14 @@ ZEND_METHOD(reflection_method, invoke)
 
 		obj_ce = Z_OBJCE_PP(params[0]);
 
-		if (!instanceof_function(obj_ce, mptr->common.scope TSRMLS_CC)) {
-			if (params) {
-				efree(params);
-			}
-			_DO_THROW("Given object is not an instance of the class this method was declared in");
+		/* This should not be required any more as you can invoke a method from any object. */
+		//if (!instanceof_function(obj_ce, mptr->common.scope TSRMLS_CC)) {
+		//	if (params) {
+		//		efree(params);
+		//	}
+		//	_DO_THROW("Given object is not an instance of the class this method was declared in");
 			/* Returns from this function */
-		}
+		//}
 
 		object_ptr = *params[0];
 	}
@@ -2877,7 +2912,7 @@ ZEND_METHOD(reflection_method, invoke)
 	fcc.initialized = 1;
 	fcc.function_handler = mptr;
 	fcc.calling_scope = obj_ce;
-	fcc.called_scope = intern->ce;
+	fcc.called_scope = obj_ce;
 	fcc.object_ptr = object_ptr;
 
 	result = zend_call_function(&fci, &fcc TSRMLS_CC);
@@ -2911,14 +2946,14 @@ ZEND_METHOD(reflection_method, invokeArgs)
 	int result;
 	zend_fcall_info fci;
 	zend_fcall_info_cache fcc;
-	zend_class_entry *obj_ce;
+	zend_class_entry *obj_ce, **ce_p;
 	zval *param_array;
 
 	METHOD_NOTSTATIC(reflection_method_ptr);
 
 	GET_REFLECTION_OBJECT_PTR(mptr);
 
-	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o!a", &object, &param_array) == FAILURE) {
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|a", &object, &param_array) == FAILURE) {
 		return;
 	}
 
@@ -2939,7 +2974,6 @@ ZEND_METHOD(reflection_method, invokeArgs)
 		}
 		return;
 	}
-
 	argc = zend_hash_num_elements(Z_ARRVAL_P(param_array));
 
 	params = safe_emalloc(sizeof(zval **), argc, 0);
@@ -2953,8 +2987,42 @@ ZEND_METHOD(reflection_method, invokeArgs)
 	 * Else, we verify that the given object is an instance of the class.
 	 */
 	if (mptr->common.fn_flags & ZEND_ACC_STATIC) {
+
+		if (IS_ZEND_STD_OBJECT(*object)) {
+			obj_ce = Z_OBJCE_P(object);
+		} else if (Z_TYPE_P(object) == IS_NULL) {
+			obj_ce = mptr->common.scope;
+		} else {
+			char *class_name;
+			int class_name_len;
+			zval tmp_zval;
+			INIT_ZVAL(tmp_zval);
+
+			if (Z_TYPE_P(object) == IS_STRING) {
+				class_name = Z_STRVAL_P(object);
+				class_name_len = Z_STRLEN_P(object);
+			} else {
+				tmp_zval = *object;
+				zval_copy_ctor(&tmp_zval);
+				convert_to_string(&tmp_zval);
+				class_name = Z_STRVAL(tmp_zval);
+				class_name_len = Z_STRLEN(tmp_zval);
+			}
+
+			if ((class_name_len == sizeof("static") - 1) &&
+				(memcmp("static", class_name, sizeof("static") - 1) == 0)) {
+				obj_ce = mptr->common.scope;
+			}
+			else if (zend_lookup_class_ex(class_name, class_name_len, NULL, 1, &ce_p TSRMLS_CC) == FAILURE) {
+				zend_error(E_WARNING, "Class '%s' not found", class_name);
+				zval_dtor(&tmp_zval);
+				RETURN_NULL();
+			} else {
+				obj_ce = *ce_p;
+			}
+			zval_dtor(&tmp_zval);
+		}
 		object = NULL;
-		obj_ce = mptr->common.scope;
 	} else {
 		if (!object) {
 			efree(params);
@@ -2966,11 +3034,12 @@ ZEND_METHOD(reflection_method, invokeArgs)
 
 		obj_ce = Z_OBJCE_P(object);
 
-		if (!instanceof_function(obj_ce, mptr->common.scope TSRMLS_CC)) {
-			efree(params);
-			_DO_THROW("Given object is not an instance of the class this method was declared in");
+		/* This should not be required any more as you can invoke a method from any object. */
+		//if (!instanceof_function(obj_ce, mptr->common.scope TSRMLS_CC)) {
+		//	efree(params);
+		//	_DO_THROW("Given object is not an instance of the class this method was declared in");
 			/* Returns from this function */
-		}
+		//}
 	}
 
 	fci.size = sizeof(fci);
@@ -2986,7 +3055,7 @@ ZEND_METHOD(reflection_method, invokeArgs)
 	fcc.initialized = 1;
 	fcc.function_handler = mptr;
 	fcc.calling_scope = obj_ce;
-	fcc.called_scope = intern->ce;
+	fcc.called_scope = obj_ce;
 	fcc.object_ptr = object;
 
 	result = zend_call_function(&fci, &fcc TSRMLS_CC);
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Apr 25 03:01:29 2024 UTC