]> granicus.if.org Git - php/commitdiff
Fixed bug #42937 (__call() method not invoked when methods are called on parent from...
authorDmitry Stogov <dmitry@php.net>
Mon, 12 Nov 2007 09:11:49 +0000 (09:11 +0000)
committerDmitry Stogov <dmitry@php.net>
Mon, 12 Nov 2007 09:11:49 +0000 (09:11 +0000)
NEWS
Zend/tests/bug42937.phpt [new file with mode: 0755]
Zend/zend_object_handlers.c

diff --git a/NEWS b/NEWS
index 9e1132ce3df369e353e942e09f73816b7dc6b9d9..abd34811f6f3eb453224ed8e2469efc64b514738 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,8 @@ PHP                                                                        NEWS
 - Fixed bug #43201 (Crash on using unitialized vals and __get/__set). (Dmitry)
 - Fixed bug #43175 (__destruct() throwing an exception with __call() causes
   segfault). (Dmitry)
+- Fixed bug #42937 (__call() method not invoked when methods are called on
+  parent from child class). (Dmitry)
 
 08 Nov 2007, PHP 5.2.5
 - Upgraded PCRE to version 7.3 (Nuno)
diff --git a/Zend/tests/bug42937.phpt b/Zend/tests/bug42937.phpt
new file mode 100755 (executable)
index 0000000..875f0d9
--- /dev/null
@@ -0,0 +1,40 @@
+--TEST--
+Bug #42937 (__call() method not invoked when methods are called on parent from child class)
+--FILE--
+<?php
+class A {
+       function __call($strMethod, $arrArgs) {
+               echo "$strMethod\n";
+       }
+}
+
+class C {
+       function __call($strMethod, $arrArgs) {
+               echo "$strMethod\n";
+       }
+}
+
+class B extends A {
+       function test() {
+               self::test1();
+               parent::test2();
+               A::test3();
+               B::test4();
+               C::test5();
+       }
+}
+
+$a = new A();
+$a->test();
+
+$b = new B();
+$b->test();
+?>
+--EXPECTF--
+test
+test1
+test2
+test3
+test4
+
+Fatal error: Call to undefined method C::test5() in %sbug42937.php on line 20
index 901c28ce689710d180200c0a683e631562876a34..e6a6e485dea146a61746648cf495b3f6f9432911 100644 (file)
@@ -831,12 +831,32 @@ ZEND_API zend_function *zend_std_get_static_method(zend_class_entry *ce, char *f
        zend_function *fbc;
 
        if (zend_hash_find(&ce->function_table, function_name_strval, function_name_strlen+1, (void **) &fbc)==FAILURE) {
-               char *class_name = ce->name;
+               if (ce->__call &&
+                   EG(This) &&
+                   Z_OBJ_HT_P(EG(This))->get_class_entry &&
+                   instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) {
+                       zend_internal_function *call_user_call = emalloc(sizeof(zend_internal_function));
 
-               if (!class_name) {
-                       class_name = "";
+                       call_user_call->type = ZEND_INTERNAL_FUNCTION;
+                       call_user_call->module = ce->module;
+                       call_user_call->handler = zend_std_call_user_call;
+                       call_user_call->arg_info = NULL;
+                       call_user_call->num_args = 0;
+                       call_user_call->scope = ce;
+                       call_user_call->fn_flags = 0;
+                       call_user_call->function_name = estrndup(function_name_strval, function_name_strlen);
+                       call_user_call->pass_rest_by_reference = 0;
+                       call_user_call->return_reference = ZEND_RETURN_VALUE;
+
+                       return (union _zend_function *)call_user_call;
+               } else {
+                       char *class_name = ce->name;
+
+                       if (!class_name) {
+                               class_name = "";
+                       }
+                       zend_error(E_ERROR, "Call to undefined method %s::%s()", class_name, function_name_strval);
                }
-               zend_error(E_ERROR, "Call to undefined method %s::%s()", class_name, function_name_strval);
        }
        if (fbc->op_array.fn_flags & ZEND_ACC_PUBLIC) {
                /* No further checks necessary, most common case */