Hi internals,

It seems that there is a bug in the way some callbacks are handled. For instance:

array('B', 'parent::who');

Here, the classname 'B' will only be used for inheritance checks with the current scope, but the actual resolution will be made using the current scope, and 'parent::who'.

According to Marcus, this is wrong, so here is two patches (+ tests) meant for HEAD [1]
and the 5_2 branch (>5.2.3) [2].

Thanks for your consideration.

Regards

1: http://patches.colder.ch/Zend/callbacks_HEAD.patch?markup
2: http://patches.colder.ch/Zend/callbacks_5_2.patch?markup

--
Etienne Kneuss
http://www.colder.ch
[EMAIL PROTECTED]

Men never do evil so completely and cheerfully as when they do it from a religious conviction.
-- Pascal

Index: ext/standard/tests/general_functions/callbacks_001.phpt
===================================================================
RCS file: ext/standard/tests/general_functions/callbacks_001.phpt
diff -N ext/standard/tests/general_functions/callbacks_001.phpt
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ ext/standard/tests/general_functions/callbacks_001.phpt     27 May 2007 
21:38:48 -0000
@@ -0,0 +1,55 @@
+--TEST--
+ZE2 Callbacks of static functions
+--FILE--
+<?php
+class A {
+    public static function who() {
+        echo "A\n";
+    }
+    public static function who2() {
+        echo "A\n";
+    }
+}
+
+class B extends A {
+    public static function who() {
+        echo "B\n";
+    }
+}
+class C extends B {
+    public function foo() {
+        call_user_func(array('parent', 'who'));
+        call_user_func(array('C', 'parent::who'));
+        call_user_func(array('B', 'parent::who'));
+        call_user_func(array('E', 'parent::who'));
+        call_user_func(array('B', 'who2'));
+        call_user_func(array('A', 'who'));
+        call_user_func(array('C', 'who'));
+    }
+}
+
+class D {
+    public static function who() {
+        echo "D\n";
+    }
+}
+
+class E extends D {
+    public static function who() {
+        echo "E\n";
+    }
+}
+
+$o = new C;
+$o->foo();
+?>
+===DONE===
+--EXPECT--
+B
+B
+A
+D
+A
+A
+B
+===DONE===
Index: Zend/zend_API.c
===================================================================
RCS file: /repository/ZendEngine2/zend_API.c,v
retrieving revision 1.296.2.27.2.30
diff -u -r1.296.2.27.2.30 zend_API.c
--- Zend/zend_API.c     16 May 2007 18:57:15 -0000      1.296.2.27.2.30
+++ Zend/zend_API.c     27 May 2007 21:38:50 -0000
@@ -2125,6 +2125,8 @@
                mlen = Z_STRLEN_P(callable) - clen - 2;
                lcname = zend_str_tolower_dup(Z_STRVAL_P(callable), clen);
                /* caution: lcname is not '\0' terminated */
+               zend_class_entry *last_scope = EG(scope);
+               EG(scope) = ce_org;
                if (clen == sizeof("self") - 1 && memcmp(lcname, "self", 
sizeof("self") - 1) == 0) {
                        *ce_ptr = EG(scope);
                } else if (clen == sizeof("parent") - 1 && memcmp(lcname, 
"parent", sizeof("parent") - 1) == 0 && EG(active_op_array)->scope) {
@@ -2132,6 +2134,7 @@
                } else if (zend_lookup_class(Z_STRVAL_P(callable), clen, &pce 
TSRMLS_CC) == SUCCESS) {
                        *ce_ptr = *pce;
                }
+               EG(scope) = last_scope;
                efree(lcname);
                if (!*ce_ptr) {
                        return 0;
Index: Zend/zend_execute_API.c
===================================================================
RCS file: /repository/ZendEngine2/zend_execute_API.c,v
retrieving revision 1.331.2.20.2.19
diff -u -r1.331.2.20.2.19 zend_execute_API.c
--- Zend/zend_execute_API.c     27 Apr 2007 08:12:24 -0000      1.331.2.20.2.19
+++ Zend/zend_execute_API.c     27 May 2007 21:38:53 -0000
@@ -750,7 +750,8 @@
                if ((colon = strstr(fname, "::")) != NULL) {
                        int clen = colon - fname;
                        int mlen = fname_len - clen - 2;
-                       zend_class_entry **pce, *ce_child = NULL;
+                       zend_class_entry **pce, *ce_child = NULL, *last_scope = 
EG(scope);
+                       EG(scope) = calling_scope;
                        if (zend_lookup_class(fname, clen, &pce TSRMLS_CC) == 
SUCCESS) {
                                ce_child = *pce;
                        } else {
@@ -765,6 +766,7 @@
                                }
                                efree(lcname);
                        }
+                       EG(scope) = last_scope;
                        if (!ce_child) {
                                zend_error(E_ERROR, "Cannot call method %s() or 
method does not exist", fname);
                                return FAILURE;
Index: Zend/zend_API.c
===================================================================
RCS file: /repository/ZendEngine2/zend_API.c,v
retrieving revision 1.433
diff -u -r1.433 zend_API.c
--- Zend/zend_API.c     16 May 2007 18:56:38 -0000      1.433
+++ Zend/zend_API.c     27 May 2007 15:31:44 -0000
@@ -2561,7 +2561,11 @@
                }
        }
        if (colon.v != NULL) {
+               zend_class_entry *last_scope = EG(scope);
+               EG(scope) = ce_org;
                *ce_ptr = zend_u_fetch_class(Z_TYPE_P(callable), 
Z_UNIVAL_P(callable), clen, ZEND_FETCH_CLASS_AUTO TSRMLS_CC);
+               EG(scope) = last_scope;
+
                if (!*ce_ptr) {
                        return 0;
                }
Index: ext/standard/tests/general_functions/callbacks_001.phpt
===================================================================
RCS file: ext/standard/tests/general_functions/callbacks_001.phpt
diff -N ext/standard/tests/general_functions/callbacks_001.phpt
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ ext/standard/tests/general_functions/callbacks_001.phpt     27 May 2007 
15:31:44 -0000
@@ -0,0 +1,55 @@
+--TEST--
+ZE2 Callbacks of static functions
+--FILE--
+<?php
+class A {
+    public static function who() {
+        echo "A\n";
+    }
+    public static function who2() {
+        echo "A\n";
+    }
+}
+
+class B extends A {
+    public static function who() {
+        echo "B\n";
+    }
+}
+class C extends B {
+    public function foo() {
+        call_user_func(array('parent', 'who'));
+        call_user_func(array('C', 'parent::who'));
+        call_user_func(array('B', 'parent::who'));
+        call_user_func(array('E', 'parent::who'));
+        call_user_func(array('B', 'who2'));
+        call_user_func(array('A', 'who'));
+        call_user_func(array('C', 'who'));
+    }
+}
+
+class D {
+    public static function who() {
+        echo "D\n";
+    }
+}
+
+class E extends D {
+    public static function who() {
+        echo "E\n";
+    }
+}
+
+$o = new C;
+$o->foo();
+?>
+===DONE===
+--EXPECT--
+B
+B
+A
+D
+A
+A
+B
+===DONE===

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to