summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS2
-rw-r--r--Zend/tests/bug53826.phpt33
-rw-r--r--Zend/zend_object_handlers.c41
3 files changed, 58 insertions, 18 deletions
diff --git a/NEWS b/NEWS
index c6b626bb53..ba6465fbcc 100644
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,8 @@ PHP NEWS
. Added missing hashtable insertion APIs for arr/obj/ref. (Sara)
. Fixed bug #75474 (function scope static variables are not bound to a unique
function). (Nikita)
+ . Fixed bug #53826 (__callStatic fired in base class through a parent call if
+ the method is private). (Nikita)
- FTP:
. Convert resource<ftp> to object \FTPConnection. (Sara)
diff --git a/Zend/tests/bug53826.phpt b/Zend/tests/bug53826.phpt
new file mode 100644
index 0000000000..3f0a069536
--- /dev/null
+++ b/Zend/tests/bug53826.phpt
@@ -0,0 +1,33 @@
+--TEST--
+Bug #53826: __callStatic fired in base class through a parent call if the method is private
+--FILE--
+<?php
+
+class A1 {
+ public function __call($method, $args) { echo "__call\n"; }
+ public static function __callStatic($method, $args) { echo "__callStatic\n"; }
+}
+
+class A2 { // A1 with private function test
+ public function __call($method, $args) { echo "__call\n"; }
+ public static function __callStatic($method, $args) { echo "__callStatic\n"; }
+ private function test() {}
+}
+
+class B1 extends A1 {
+ public function test(){ parent::test(); }
+}
+
+class B2 extends A2 {
+ public function test(){ parent::test(); }
+}
+
+$test1 = new B1;
+$test2 = new B2;
+$test1->test();
+$test2->test();
+
+?>
+--EXPECT--
+__call
+__call
diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c
index e99af731f9..b903afb8ba 100644
--- a/Zend/zend_object_handlers.c
+++ b/Zend/zend_object_handlers.c
@@ -1263,11 +1263,29 @@ static zend_always_inline zend_function *zend_get_user_callstatic_function(zend_
}
/* }}} */
+static zend_always_inline zend_function *get_static_method_fallback(
+ zend_class_entry *ce, zend_string *function_name)
+{
+ zend_object *object;
+ if (ce->__call &&
+ (object = zend_get_this_object(EG(current_execute_data))) != NULL &&
+ instanceof_function(object->ce, ce)) {
+ /* Call the top-level defined __call().
+ * see: tests/classes/__call_004.phpt */
+
+ ZEND_ASSERT(object->ce->__call);
+ return zend_get_user_call_function(object->ce, function_name);
+ } else if (ce->__callstatic) {
+ return zend_get_user_callstatic_function(ce, function_name);
+ } else {
+ return NULL;
+ }
+}
+
ZEND_API zend_function *zend_std_get_static_method(zend_class_entry *ce, zend_string *function_name, const zval *key) /* {{{ */
{
zend_function *fbc = NULL;
zend_string *lc_function_name;
- zend_object *object;
zend_class_entry *scope;
if (EXPECTED(key != NULL)) {
@@ -1293,19 +1311,7 @@ ZEND_API zend_function *zend_std_get_static_method(zend_class_entry *ce, zend_st
if (UNEXPECTED(!key)) {
zend_string_release_ex(lc_function_name, 0);
}
- if (ce->__call &&
- (object = zend_get_this_object(EG(current_execute_data))) != NULL &&
- instanceof_function(object->ce, ce)) {
- /* Call the top-level defined __call().
- * see: tests/classes/__call_004.phpt */
-
- ZEND_ASSERT(object->ce->__call);
- return zend_get_user_call_function(object->ce, function_name);
- } else if (ce->__callstatic) {
- return zend_get_user_callstatic_function(ce, function_name);
- } else {
- return NULL;
- }
+ return get_static_method_fallback(ce, function_name);
}
} while (0);
@@ -1321,12 +1327,11 @@ ZEND_API zend_function *zend_std_get_static_method(zend_class_entry *ce, zend_st
if (UNEXPECTED(fbc->common.scope != scope)) {
if (UNEXPECTED(fbc->op_array.fn_flags & ZEND_ACC_PRIVATE)
|| UNEXPECTED(!zend_check_protected(zend_get_function_root_class(fbc), scope))) {
- if (ce->__callstatic) {
- fbc = zend_get_user_callstatic_function(ce, function_name);
- } else {
+ zend_function *fallback_fbc = get_static_method_fallback(ce, function_name);
+ if (!fallback_fbc) {
zend_bad_method_call(fbc, function_name, scope);
- fbc = NULL;
}
+ fbc = fallback_fbc;
}
}
}