Attached is a patch which exports an internals hook in zend_class_entry
for fetching function pointers similar to the object hook get_method()
available to instance methods.
This patch also exports a userspace hook __call_static() which operates
in the fashion of the current __call() magic method, but for static calls.
Wez called for some functionality like this a few weeks ago for a COM
wrapper (or something similar), and I noticed there was actually a
comment in the engine about how this should eventually be done anyway...
Usage example:
class foo
{
public static function __call_static($fname, $args)
{
echo foo::{$fname}() called staticly with ,
count($args), parameters\n;
}
}
foo::randomMethod(1,2,3);
I considered setting get_static_method to zend_std_get_static_method()
by default (avoiding the if set check during runtime), but all the other
hoooks follow this pattern so I went with consistency.
If noone comments to the negative, I'll commit next friday (7/20)...
-Sara
Index: Zend/zend.h
===
RCS file: /repository/ZendEngine2/zend.h,v
retrieving revision 1.334
diff -u -p -r1.334 zend.h
--- Zend/zend.h 26 Apr 2007 19:08:24 - 1.334
+++ Zend/zend.h 14 Jul 2007 00:42:05 -
@@ -378,6 +378,7 @@ struct _zend_class_entry {
union _zend_function *__unset;
union _zend_function *__isset;
union _zend_function *__call;
+ union _zend_function *__call_static;
union _zend_function *__tostring;
union _zend_function *serialize_func;
union _zend_function *unserialize_func;
@@ -388,6 +389,7 @@ struct _zend_class_entry {
zend_object_value (*create_object)(zend_class_entry *class_type
TSRMLS_DC);
zend_object_iterator *(*get_iterator)(zend_class_entry *ce, zval
*object, int by_ref TSRMLS_DC);
int (*interface_gets_implemented)(zend_class_entry *iface,
zend_class_entry *class_type TSRMLS_DC); /* a class implements this interface */
+ union _zend_function *(*get_static_method)(zend_class_entry *ce, zstr
method, int method_len TSRMLS_DC);
/* serializer callbacks */
int (*serialize)(zval *object, int *type, zstr *buffer, zend_uint
*buf_len, zend_serialize_data *data TSRMLS_DC);
Index: Zend/zend_API.c
===
RCS file: /repository/ZendEngine2/zend_API.c,v
retrieving revision 1.439
diff -u -p -r1.439 zend_API.c
--- Zend/zend_API.c 13 Jul 2007 23:51:51 - 1.439
+++ Zend/zend_API.c 14 Jul 2007 00:42:05 -
@@ -2026,6 +2026,9 @@ ZEND_API void zend_check_magic_method_im
} else if (lcname_len == sizeof(ZEND_CALL_FUNC_NAME) - 1
ZEND_U_EQUAL(utype, lcname, lcname_len, ZEND_CALL_FUNC_NAME,
sizeof(ZEND_CALL_FUNC_NAME)-1) fptr-common.num_args != 2) {
zend_error(error_type, Method %v::%s() must take exactly 2
arguments, ce-name, ZEND_CALL_FUNC_NAME);
+ } else if (lcname_len == sizeof(ZEND_CALL_STATIC_FUNC_NAME) - 1
+ ZEND_U_EQUAL(utype, lcname, lcname_len, ZEND_CALL_STATIC_FUNC_NAME,
sizeof(ZEND_CALL_STATIC_FUNC_NAME)-1) fptr-common.num_args != 2) {
+ zend_error(error_type, Method %v::%s() must take exactly 2
arguments, ce-name, ZEND_CALL_STATIC_FUNC_NAME);
} else if (lcname_len == sizeof(ZEND_TOSTRING_FUNC_NAME) - 1
ZEND_U_EQUAL(utype, lcname, lcname_len, ZEND_TOSTRING_FUNC_NAME,
sizeof(ZEND_TOSTRING_FUNC_NAME)-1) fptr-common.num_args != 0) {
zend_error(error_type, Method %v::%s() cannot take arguments,
ce-name, ZEND_TOSTRING_FUNC_NAME);
@@ -2043,7 +2046,7 @@ ZEND_API int zend_register_functions(zen
int count=0, unload=0;
HashTable *target_function_table = function_table;
int error_type;
- zend_function *ctor = NULL, *dtor = NULL, *clone = NULL, *__get = NULL,
*__set = NULL, *__unset = NULL, *__isset = NULL, *__call = NULL, *__tostring =
NULL;
+ zend_function *ctor = NULL, *dtor = NULL, *clone = NULL, *__get = NULL,
*__set = NULL, *__unset = NULL, *__isset = NULL, *__call = NULL, *__call_static
= NULL, *__tostring = NULL;
char *lowercase_name;
int fname_len;
zstr lc_class_name = NULL_ZSTR;
@@ -2186,6 +2189,8 @@ ZEND_API int zend_register_functions(zen
clone = reg_function;
} else if ((fname_len == sizeof(ZEND_CALL_FUNC_NAME)-1)
!memcmp(lowercase_name, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME))) {
__call = reg_function;
+ } else if ((fname_len ==
sizeof(ZEND_CALL_STATIC_FUNC_NAME)-1) !memcmp(lowercase_name,
ZEND_CALL_STATIC_FUNC_NAME, sizeof(ZEND_CALL_STATIC_FUNC_NAME))) {
+ __call_static = reg_function;
} else if ((fname_len ==
sizeof(ZEND_TOSTRING_FUNC_NAME)-1)