]> granicus.if.org Git - php/commitdiff
- Simplify call_user_func/call_user_func_array implementation
authorMarcus Boerger <helly@php.net>
Thu, 8 Feb 2007 15:31:01 +0000 (15:31 +0000)
committerMarcus Boerger <helly@php.net>
Thu, 8 Feb 2007 15:31:01 +0000 (15:31 +0000)
- Allow call_user_func/call_user_func_array to return reference

ext/standard/basic_functions.c
ext/standard/tests/general_functions/bug40398.phpt
ext/standard/tests/general_functions/call_user_func_return.phpt [new file with mode: 0755]

index 0b3fa8df75bbc1995100b272e8349674c1012faf..0fd0bae0aa7ff109e6143a20000e365d3d86d963 100644 (file)
@@ -787,7 +787,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_call_user_func, 0, 0, 1)
 ZEND_END_ARG_INFO()
 
 static
-ZEND_BEGIN_ARG_INFO(arginfo_call_user_func_array, 0)
+ZEND_BEGIN_ARG_INFO_EX(arginfo_call_user_func_array, 0, 0, 2)
        ZEND_ARG_INFO(0, function_name)
        ZEND_ARG_INFO(0, parameters) /* ARRAY_INFO(0, parameters, 1) */
 ZEND_END_ARG_INFO()
@@ -5044,43 +5044,29 @@ PHP_FUNCTION(error_get_last)
 }
 /* }}} */
 
-/* {{{ proto mixed call_user_func(string function_name [, mixed parmeter] [, mixed ...]) U
+/* {{{ proto mixed call_user_func(mixed function_name [, mixed parmeter] [, mixed ...]) U
    Call a user function which is the first parameter */
 PHP_FUNCTION(call_user_func)
 {
-       zval ***params = NULL;
-       int n_params = 0;
-       zval *retval_ptr;
-       zval *callback, name;
+       zval *retval_ptr = return_value;
        zend_fcall_info fci;
-       zend_fcall_info_cache fci_cache = empty_fcall_info_cache;
-
-       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z*", &callback, &params, &n_params) == FAILURE) {
-               return;
-       }
+       zend_fcall_info_cache fci_cache;
 
-       if (zend_fcall_info_init(callback, &fci, &fci_cache, NULL TSRMLS_CC) == FAILURE) {
-               php_error_docref(NULL TSRMLS_CC, E_WARNING, "first parameter is expected to be a valid callback");
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "f*", &fci, &fci_cache, &fci.params, &fci.param_count) == FAILURE) {
                return;
        }
 
-       fci.retval_ptr_ptr = &retval_ptr;
-       fci.params = params;
-       fci.param_count = n_params;
-       fci.no_separation = 0;
+       fci.retval_ptr_ptr = return_value_ptr;
 
        if (zend_call_function(&fci, &fci_cache TSRMLS_CC) == SUCCESS) {
-               if (retval_ptr) {
-                       COPY_PZVAL_TO_ZVAL(*return_value, retval_ptr);
-               }
-       } else {
-               zend_is_callable(callback, IS_CALLABLE_CHECK_SYNTAX_ONLY, &name);
-               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to call %R()", Z_TYPE(name), Z_UNIVAL(name));
-               zval_dtor(&name);
+               zval_ptr_dtor(&retval_ptr);
+       }
+       if (!*return_value_ptr) {
+               ALLOC_INIT_ZVAL(*return_value_ptr);
        }
 
-       if (params) {
-               efree(params);
+       if (fci.params) {
+               efree(fci.params);
        }
 }
 /* }}} */
@@ -5089,58 +5075,26 @@ PHP_FUNCTION(call_user_func)
    Call a user function which is the first parameter with the arguments contained in array */
 PHP_FUNCTION(call_user_func_array)
 {
-       zval ***func_params, *callback, *params;
-       zval *retval_ptr;
-       HashTable *func_params_ht;
-       zval name;
+       zval *params, *retval_ptr = return_value;
        zend_fcall_info fci;
-       zend_fcall_info_cache fci_cache = empty_fcall_info_cache;
-       int count;
-       int current = 0;
-
-       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "za/", &callback, &params) == FAILURE) {
-               return;
-       }
+       zend_fcall_info_cache fci_cache;
 
-       if (zend_fcall_info_init(callback, &fci, &fci_cache, NULL TSRMLS_CC) == FAILURE) {
-               php_error_docref(NULL TSRMLS_CC, E_WARNING, "first parameter is expected to be a valid callback");
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "fa/", &fci, &fci_cache, &params) == FAILURE) {
                return;
        }
 
-       func_params_ht = Z_ARRVAL_P(params);
-
-       count = zend_hash_num_elements(func_params_ht);
-       if (count) {
-               func_params = safe_emalloc(sizeof(zval **), count, 0);
-
-               for (zend_hash_internal_pointer_reset(func_params_ht);
-                        zend_hash_get_current_data(func_params_ht, (void **) &func_params[current]) == SUCCESS;
-                        zend_hash_move_forward(func_params_ht))
-               {
-                       current++;
-               }
-       } else {
-               func_params = NULL;
-       }
+       fci.retval_ptr_ptr = return_value_ptr;
 
-       fci.retval_ptr_ptr = &retval_ptr;
-       fci.params = func_params;
-       fci.param_count = count;
-       fci.no_separation = 0;
+       zend_fcall_info_args(&fci, params TSRMLS_CC);
 
        if (zend_call_function(&fci, &fci_cache TSRMLS_CC) == SUCCESS) {
-               if (retval_ptr) {
-                       COPY_PZVAL_TO_ZVAL(*return_value, retval_ptr);
-               }
-       } else {
-               zend_is_callable(callback, IS_CALLABLE_CHECK_SYNTAX_ONLY, &name);
-               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to call %R()", Z_TYPE(name), Z_UNIVAL(name));
-               zval_dtor(&name);
+               zval_ptr_dtor(&retval_ptr);
        }
-
-       if (func_params) {
-               efree(func_params);
+       if (!*return_value_ptr) {
+               ALLOC_INIT_ZVAL(*return_value_ptr);
        }
+
+       zend_fcall_info_args_clear(&fci, 1);
 }
 /* }}} */
 
index ab5d52e05a01e1bc9fb4dde7e341fd8bfa3d80a2..d64a9fdf20b26db2c0b5f379a7f75c70f89b1441 100755 (executable)
@@ -1,5 +1,5 @@
 --TEST--
-Bug: #40398 (parent and self callback functions erroneously called statically)
+Bug #40398 (parent and self callback functions erroneously called statically)
 --FILE--
 <?php
 
@@ -78,11 +78,11 @@ new Derived_6('6');
 Base::__construct(1)
 Base::__construct(2)
 
-Warning: call_user_func_array(): first parameter is expected to be a valid callback in %sbug40398.php on line %d
+Warning: call_user_func_array() expects parameter 1 to be valid callback, string given in %sbug40398.php on line %d
 
-Warning: call_user_func_array(): first parameter is expected to be a valid callback in %sbug40398.php on line %d
+Warning: call_user_func_array() expects parameter 1 to be valid callback, string given in %sbug40398.php on line %d
 
-Warning: call_user_func_array(): first parameter is expected to be a valid callback in %sbug40398.php on line %d
+Warning: call_user_func_array() expects parameter 1 to be valid callback, array given in %sbug40398.php on line %d
 
-Warning: call_user_func_array(): first parameter is expected to be a valid callback in %sbug40398.php on line %d
-===DONE===
\ No newline at end of file
+Warning: call_user_func_array() expects parameter 1 to be valid callback, array given in %sbug40398.php on line %d
+===DONE===
diff --git a/ext/standard/tests/general_functions/call_user_func_return.phpt b/ext/standard/tests/general_functions/call_user_func_return.phpt
new file mode 100755 (executable)
index 0000000..1697a81
--- /dev/null
@@ -0,0 +1,44 @@
+--TEST--
+call_user_func() and return value
+--FILE--
+<?php
+
+$t1 = 'test1';
+
+function test1($arg1, $arg2)
+{
+       global $t1;
+       echo "$arg1 $arg2\n";
+       return $t1;
+}
+
+$t2 = 'test2';
+
+function & test2($arg1, $arg2)
+{
+       global $t2;
+       echo "$arg1 $arg2\n";
+       return $t2;
+}
+
+function test($func)
+{
+       debug_zval_dump($func('Direct', 'Call'));
+       debug_zval_dump(call_user_func_array($func, array('User', 'Func')));
+}
+
+test('test1');
+test('test2');
+
+?>
+===DONE===
+--EXPECTF--
+Direct Call
+string(5) "test1" refcount(1)
+User Func
+string(5) "test1" refcount(1)
+Direct Call
+string(5) "test2" refcount(2)
+User Func
+string(5) "test2" refcount(2)
+===DONE===