summaryrefslogtreecommitdiff
path: root/ext/overload
diff options
context:
space:
mode:
authorAndrei Zmievski <andrei@php.net>2001-12-07 05:46:02 +0000
committerAndrei Zmievski <andrei@php.net>2001-12-07 05:46:02 +0000
commit9789e43af1e8e9888bbd8fb8470e7eb7f77d1535 (patch)
tree51cd3f4bda011d82847725bd6ba8118176fcb9df /ext/overload
parent1b35f3bcfc5c873fea881876b0d3043e93038bcc (diff)
downloadphp-git-9789e43af1e8e9888bbd8fb8470e7eb7f77d1535.tar.gz
Support overloaded method calls via __call().
Diffstat (limited to 'ext/overload')
-rw-r--r--ext/overload/overload.c68
1 files changed, 58 insertions, 10 deletions
diff --git a/ext/overload/overload.c b/ext/overload/overload.c
index 1a6d1a6fe3..8013c49bd1 100644
--- a/ext/overload/overload.c
+++ b/ext/overload/overload.c
@@ -19,7 +19,7 @@
/*
* TODO:
- * - provide a way for user to enable/disabling overloading of get/set/call
+ * + provide a way for user to enable/disabling overloading of get/set/call
* individually
* - call original overloaded handlers if necessary
* + use local copy of CE with NULL'ed out handler when calling object's
@@ -137,7 +137,7 @@ static int call_get_handler(zval *object, zval *prop_name, zval **prop_value TSR
int call_result;
zend_class_entry temp_ce, *orig_ce;
zval result, *result_ptr = &result;
- zval method_name;
+ zval get_handler;
zval **args[2];
zval *retval = NULL;
oo_class_data oo_data;
@@ -158,13 +158,13 @@ static int call_get_handler(zval *object, zval *prop_name, zval **prop_value TSR
result_ptr->refcount = 1;
ZVAL_NULL(result_ptr);
- ZVAL_STRINGL(&method_name, GET_HANDLER, sizeof(GET_HANDLER)-1, 0);
+ ZVAL_STRINGL(&get_handler, GET_HANDLER, sizeof(GET_HANDLER)-1, 0);
args[0] = &prop_name;
args[1] = &result_ptr;
call_result = call_user_function_ex(NULL,
&object,
- &method_name,
+ &get_handler,
&retval,
2, args,
0, NULL TSRMLS_CC);
@@ -203,7 +203,7 @@ int call_set_handler(zval *object, zval *prop_name, zval *value TSRMLS_DC)
{
int call_result;
zend_class_entry temp_ce, *orig_ce;
- zval method_name;
+ zval set_handler;
zval *value_copy;
zval **args[2];
zval *retval = NULL;
@@ -221,7 +221,7 @@ int call_set_handler(zval *object, zval *prop_name, zval *value TSRMLS_DC)
orig_ce = Z_OBJCE_P(object);
Z_OBJCE_P(object) = &temp_ce;
- ZVAL_STRINGL(&method_name, SET_HANDLER, sizeof(SET_HANDLER)-1, 0);
+ ZVAL_STRINGL(&set_handler, SET_HANDLER, sizeof(SET_HANDLER)-1, 0);
if (value->refcount == 0) {
MAKE_STD_ZVAL(value_copy);
*value_copy = *value;
@@ -233,7 +233,7 @@ int call_set_handler(zval *object, zval *prop_name, zval *value TSRMLS_DC)
call_result = call_user_function_ex(NULL,
&object,
- &method_name,
+ &set_handler,
&retval,
2, args,
0, NULL TSRMLS_CC);
@@ -417,6 +417,52 @@ static int overload_set_property(zend_property_reference *property_reference, zv
static void overload_call_method(INTERNAL_FUNCTION_PARAMETERS, zend_property_reference *property_reference)
{
+ zval ***args;
+ zval *retval = NULL;
+ int call_result;
+ zend_class_entry temp_ce, *orig_ce;
+ zval *object = property_reference->object;
+ zval call_handler, method_name, *method_name_ptr = &method_name;
+ zend_overloaded_element *method = (zend_overloaded_element *)property_reference->elements_list->tail->data;
+
+ args = (zval ***)emalloc((ZEND_NUM_ARGS() + 1) * sizeof(zval **));
+
+ if (zend_get_parameters_array_ex(ZEND_NUM_ARGS(), &args[1]) == FAILURE) {
+ efree(args);
+ php_error(E_WARNING, "unable to obtain arguments");
+ return;
+ }
+
+ temp_ce = *Z_OBJCE_P(object);
+ DISABLE_HANDLERS(temp_ce);
+ orig_ce = Z_OBJCE_P(object);
+ Z_OBJCE_P(object) = &temp_ce;
+
+ ZVAL_STRINGL(&call_handler, CALL_HANDLER, sizeof(CALL_HANDLER)-1, 0);
+ ZVAL_STRINGL(&method_name, Z_STRVAL(method->element), Z_STRLEN(method->element), 0);
+ INIT_PZVAL(method_name_ptr);
+ args[0] = &method_name_ptr;
+
+ call_result = call_user_function_ex(NULL,
+ &object,
+ &call_handler,
+ &retval,
+ ZEND_NUM_ARGS() + 1, args,
+ 0, NULL TSRMLS_CC);
+ /* Restore object's original CE. */
+ Z_OBJCE_P(object) = orig_ce;
+
+ if (call_result == FAILURE || !retval) {
+ efree(args);
+ php_error(E_WARNING, "unable to call %s::__call() handler", orig_ce->name);
+ return;
+ }
+
+ *return_value = *retval;
+ INIT_PZVAL(return_value);
+ FREE_ZVAL(retval);
+ efree(args);
+ zval_dtor(&method->element);
}
/* {{{ proto void overload(string class_entry)
@@ -455,9 +501,11 @@ PHP_FUNCTION(overload)
} else
oo_data.handle_property_set = NULL;
- /*
- oo_data.handle_function_call = ce->handle_function_call;
- */
+ if (zend_hash_exists(&ce->function_table, CALL_HANDLER, sizeof(CALL_HANDLER))) {
+ oo_data.handle_function_call = ce->handle_function_call;
+ ce->handle_function_call = overload_call_method;
+ } else
+ oo_data.handle_function_call = NULL;
zend_hash_index_update(&OOG(overloaded_classes), (long)ce, &oo_data, sizeof(oo_data), NULL);