]> granicus.if.org Git - php/commitdiff
MFH: Implement forward_static_call(_array) to complete LSB. Patch by Mike Lively
authorEtienne Kneuss <colder@php.net>
Mon, 7 Apr 2008 10:44:59 +0000 (10:44 +0000)
committerEtienne Kneuss <colder@php.net>
Mon, 7 Apr 2008 10:44:59 +0000 (10:44 +0000)
NEWS
ext/standard/basic_functions.c
ext/standard/basic_functions.h
ext/standard/tests/class_object/forward_static_call_001.phpt [new file with mode: 0755]
ext/standard/tests/class_object/forward_static_call_002.phpt [new file with mode: 0755]
ext/standard/tests/class_object/forward_static_call_003.phpt [new file with mode: 0755]

diff --git a/NEWS b/NEWS
index 81a8aa5b5f0359029a88a1dea2836e41de814ca7..d9cc1f10504f96eeb27d1701c904b848527de837 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -86,6 +86,7 @@ PHP                                                                        NEWS
 - Added PREG_BAD_UTF8_OFFSET_ERROR constant. (Nuno)
 - Added request_order INI variable to control specifically $_REQUEST 
   behavior. (Stas)
+- Added forward_static_call(_array) to complete LSB. (Mike Lively)
 
 - Improved PHP runtime speed and memory usage:
   . Replaced flex based scanner with re2c based scanner. (Marcus, Nuno, Scott)
index e2acdec385addbfebac7e838213f5a290d249c39..65bff0c331f97359c8fd578cb3b009c0aed55f59 100644 (file)
@@ -810,6 +810,19 @@ ZEND_BEGIN_ARG_INFO(arginfo_call_user_method_array, 0)
        ZEND_ARG_INFO(0, params) /* ARRAY_INFO(0, params, 1) */
 ZEND_END_ARG_INFO()
 
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_forward_static_call, 0, 0, 1)
+       ZEND_ARG_INFO(0, function_name)
+       ZEND_ARG_INFO(0, parameter)
+       ZEND_ARG_INFO(0, ...)
+ZEND_END_ARG_INFO()
+
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_forward_static_call_array, 0, 0, 2)
+       ZEND_ARG_INFO(0, function_name)
+       ZEND_ARG_INFO(0, parameters) /* ARRAY_INFO(0, parameters, 1) */
+ZEND_END_ARG_INFO()
+
 static
 ZEND_BEGIN_ARG_INFO(arginfo_register_shutdown_function, 0)
        ZEND_ARG_INFO(0, function_name)
@@ -3364,6 +3377,8 @@ const zend_function_entry basic_functions[] = { /* {{{ */
        PHP_FE(call_user_func_array,                                                                                    arginfo_call_user_func_array)
        PHP_DEP_FE(call_user_method,                                                                                    arginfo_call_user_method)
        PHP_DEP_FE(call_user_method_array,                                                                              arginfo_call_user_method_array)
+       PHP_FE(forward_static_call,                                                                                     arginfo_forward_static_call)
+       PHP_FE(forward_static_call_array,                                                                               arginfo_forward_static_call_array)
        PHP_FE(serialize,                                                                                                               arginfo_serialize)
        PHP_FE(unserialize,                                                                                                             arginfo_unserialize)
 
@@ -5228,6 +5243,67 @@ PHP_FUNCTION(call_user_method_array)
 }
 /* }}} */
 
+/* {{{ proto mixed forward_static_call(mixed function_name [, mixed parmeter] [, mixed ...]) U
+   Call a user function which is the first parameter */
+PHP_FUNCTION(forward_static_call)
+{
+       zval *retval_ptr = NULL;
+       zend_fcall_info fci;
+       zend_fcall_info_cache fci_cache;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "f*", &fci, &fci_cache, &fci.params, &fci.param_count) == FAILURE) {
+               return;
+       }
+
+       if (!EG(active_op_array)->scope) {
+               zend_error(E_ERROR, "Cannot call forward_static_call() when no class scope is active");
+       }
+
+       fci.retval_ptr_ptr = &retval_ptr;
+
+       if (EG(called_scope) &&
+               instanceof_function(EG(called_scope), fci_cache.calling_scope TSRMLS_CC)) {
+                       fci_cache.calling_scope = EG(called_scope);
+       }
+       
+       if (zend_call_function(&fci, &fci_cache TSRMLS_CC) == SUCCESS && fci.retval_ptr_ptr && *fci.retval_ptr_ptr) {
+               COPY_PZVAL_TO_ZVAL(*return_value, *fci.retval_ptr_ptr);
+       }
+
+       if (fci.params) {
+               efree(fci.params);
+       }
+}
+/* }}} */
+
+/* {{{ proto mixed call_user_func_array(string function_name, array parameters) U
+   Call a user function which is the first parameter with the arguments contained in array */
+PHP_FUNCTION(forward_static_call_array)
+{
+       zval *params, *retval_ptr = NULL;
+       zend_fcall_info fci;
+       zend_fcall_info_cache fci_cache;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "fa/", &fci, &fci_cache, &params) == FAILURE) {
+               return;
+       }
+
+       zend_fcall_info_args(&fci, params TSRMLS_CC);
+       fci.retval_ptr_ptr = &retval_ptr;
+
+       if (EG(called_scope) &&
+               instanceof_function(EG(called_scope), fci_cache.calling_scope TSRMLS_CC)) {
+                       fci_cache.calling_scope = EG(called_scope);
+       }
+
+       if (zend_call_function(&fci, &fci_cache TSRMLS_CC) == SUCCESS && fci.retval_ptr_ptr && *fci.retval_ptr_ptr) {
+               COPY_PZVAL_TO_ZVAL(*return_value, *fci.retval_ptr_ptr);
+       }
+
+       zend_fcall_info_args_clear(&fci, 1);
+}
+/* }}} */
+
 void user_shutdown_function_dtor(php_shutdown_function_entry *shutdown_function_entry) /* {{{ */
 {
        int i;
index 23e7e87701f0dea93f2c64124ab271415a83c288..dfb446c9b42f2cf97c7c225ac23a56d7d7f49842 100644 (file)
@@ -84,6 +84,8 @@ PHP_FUNCTION(call_user_func);
 PHP_FUNCTION(call_user_func_array);
 PHP_FUNCTION(call_user_method);
 PHP_FUNCTION(call_user_method_array);
+PHP_FUNCTION(forward_static_call);
+PHP_FUNCTION(forward_static_call_array);
 
 PHP_FUNCTION(register_shutdown_function);
 PHP_FUNCTION(highlight_file);
diff --git a/ext/standard/tests/class_object/forward_static_call_001.phpt b/ext/standard/tests/class_object/forward_static_call_001.phpt
new file mode 100755 (executable)
index 0000000..2b3a8dd
--- /dev/null
@@ -0,0 +1,83 @@
+--TEST--
+forward_static_call() called from outside of a method.
+--FILE--
+<?php
+
+class A
+{
+       const NAME = 'A';
+       public static function test() {
+               echo static::NAME, "\n";
+       }
+}
+
+class B extends A
+{
+       const NAME = 'B';
+
+       public static function test() {
+               echo self::NAME, "\n";
+               forward_static_call(array('parent', 'test'));
+       }
+
+       public static function test2() {
+               echo self::NAME, "\n";
+               forward_static_call(array('self', 'test'));
+       }
+
+       public static function test3() {
+               echo self::NAME, "\n";
+               forward_static_call(array('A', 'test'));
+       }
+}
+
+class C extends B
+{
+       const NAME = 'C';
+
+       public static function test()
+       {
+               echo self::NAME, "\n";
+               forward_static_call(array('A', 'test'));
+       }
+}
+
+A::test();
+echo "-\n";
+B::test();
+echo "-\n";
+B::test2();
+echo "-\n";
+B::test3();
+echo "-\n";
+C::test();
+echo "-\n";
+C::test2();
+echo "-\n";
+C::test3();
+
+?>
+===DONE===
+--EXPECTF--
+A
+-
+B
+B
+-
+B
+B
+B
+-
+B
+B
+-
+C
+C
+-
+B
+B
+C
+-
+B
+C
+===DONE===
diff --git a/ext/standard/tests/class_object/forward_static_call_002.phpt b/ext/standard/tests/class_object/forward_static_call_002.phpt
new file mode 100755 (executable)
index 0000000..58c4efd
--- /dev/null
@@ -0,0 +1,21 @@
+--TEST--
+forward_static_call() from outside of a class method.
+--FILE--
+<?php
+
+class A
+{
+       public static function test() {
+               echo "A\n";
+       }
+}
+
+function test() {
+       forward_static_call(array('A', 'test'));
+}
+
+test();
+
+?>
+--EXPECTF--
+Fatal error: Cannot call forward_static_call() when no class scope is active in %s on line %d
diff --git a/ext/standard/tests/class_object/forward_static_call_003.phpt b/ext/standard/tests/class_object/forward_static_call_003.phpt
new file mode 100755 (executable)
index 0000000..2ea102e
--- /dev/null
@@ -0,0 +1,51 @@
+--TEST--
+forward_static_call() calling outside of the inheritance chain.
+--FILE--
+<?php
+
+class A
+{
+       const NAME = 'A';
+       public static function test() {
+               echo static::NAME, "\n";
+       }
+}
+
+class B extends A
+{
+       const NAME = 'B';
+
+       public static function test() {
+               echo self::NAME, "\n";
+               forward_static_call(array('parent', 'test'));
+       }
+}
+
+class C
+{
+       const NAME = 'C';
+
+       public static function test() {
+               echo self::NAME, "\n";
+               forward_static_call(array('B', 'test'));
+       }
+}
+
+A::test();
+echo "-\n";
+B::test();
+echo "-\n";
+C::test();
+
+?>
+===DONE===
+--EXPECTF--
+A
+-
+B
+B
+-
+C
+B
+B
+===DONE===