]> granicus.if.org Git - php/commitdiff
- Bugfix #37632 (Protected method access problem)
authorMarcus Boerger <helly@php.net>
Mon, 29 May 2006 19:57:43 +0000 (19:57 +0000)
committerMarcus Boerger <helly@php.net>
Mon, 29 May 2006 19:57:43 +0000 (19:57 +0000)
Zend/tests/bug37632.phpt [new file with mode: 0755]
Zend/zend_compile.c
Zend/zend_object_handlers.c

diff --git a/Zend/tests/bug37632.phpt b/Zend/tests/bug37632.phpt
new file mode 100755 (executable)
index 0000000..fb72f89
--- /dev/null
@@ -0,0 +1,135 @@
+--TEST--
+Bug #37632 (Protected method access problem)
+--FILE--
+<?php
+
+class A1
+{
+       protected function test()
+       {
+               echo __METHOD__ . "\n";
+       }
+}
+
+class B1 extends A1
+{
+       public function doTest(A1 $obj)
+       {
+               echo __METHOD__ . "\n";
+               $obj->test();
+       }
+}
+
+class C1 extends A1
+{
+       protected function test()
+       {
+               echo __METHOD__ . "\n";
+       }
+}
+
+$b = new B1;
+$b->doTest(new C1);
+
+class A2
+{
+       static protected function test()
+       {
+               echo __METHOD__ . "\n";
+       }
+}
+
+class B2 extends A2
+{
+       static public function doTest(A2 $obj)
+       {
+               echo __METHOD__ . "\n";
+               $obj->test();
+       }
+}
+
+class C2 extends A2
+{
+       static protected function test()
+       {
+               echo __METHOD__ . "\n";
+       }
+}
+
+B2::doTest(new C2);
+
+/* Right now Ctor's cannot be made protected when defined in a ctor. That is
+ * we cannot decrease visibility.
+ *
+
+interface Ctor
+{
+       function __construct($x);
+}
+
+class A3 implements Ctor
+{
+       protected function __construct()
+       {
+               echo __METHOD__ . "\n";
+       }
+}
+
+class B3 extends A3
+{
+       static public function doTest()
+       {
+               echo __METHOD__ . "\n";
+               new C3;
+       }
+}
+
+class C3 extends A3
+{
+       protected function __construct()
+       {
+               echo __METHOD__ . "\n";
+       }
+}
+
+B3::doTest();
+
+*/
+
+class A4
+{
+       protected function __construct()
+       {
+               echo __METHOD__ . "\n";
+       }
+}
+
+class B4 extends A4
+{
+       static public function doTest()
+       {
+               echo __METHOD__ . "\n";
+               new C4;
+       }
+}
+
+class C4 extends A4
+{
+       protected function __construct()
+       {
+               echo __METHOD__ . "\n";
+       }
+}
+
+B4::doTest();
+
+?>
+===DONE===
+--EXPECTF--
+B1::doTest
+C1::test
+B2::doTest
+C2::test
+B4::doTest
+
+Fatal error: Call to protected C4::__construct() from context 'B4' in %sbug37632.php on line %d
index 5c0aed777e1c093c5be257126e8df65f5ca32d95..ed6bf9646eac3503d427b26685df403ef0ff6202 100644 (file)
@@ -2163,8 +2163,9 @@ static zend_bool do_inherit_method_check(HashTable *child_function_table, zend_f
        if (parent_flags & ZEND_ACC_ABSTRACT) {
                child->common.fn_flags |= ZEND_ACC_IMPLEMENTED_ABSTRACT;
                child->common.prototype = parent;
-       } else {
-               child->common.prototype = parent->common.prototype;
+       } else if (!(parent->common.fn_flags & ZEND_ACC_CTOR) || (parent->common.prototype && parent->common.prototype->common.scope->ce_flags && ZEND_ACC_INTERFACE)) {
+               /* ctors only have a prototype if it comes from an interface */
+               child->common.prototype = parent->common.prototype ? parent->common.prototype : parent;
        }
 
 
index 6205518e2f6fd04b42705857704236670784c58f..3966731626a7f71e3c94c4ca46489c8877b00dea 100644 (file)
@@ -732,6 +732,12 @@ ZEND_API int zend_check_protected(zend_class_entry *ce, zend_class_entry *scope)
 }
 
 
+static inline zend_class_entry * zend_get_function_root_class(zend_function *fbc)
+{
+       return fbc->common.prototype ? fbc->common.prototype->common.scope : fbc->common.scope;
+}
+
+
 static union _zend_function *zend_std_get_method(zval **object_ptr, zstr method_name, int method_len TSRMLS_DC)
 {
        zend_object *zobj;
@@ -799,7 +805,7 @@ static union _zend_function *zend_std_get_method(zval **object_ptr, zstr method_
        } else if ((fbc->common.fn_flags & ZEND_ACC_PROTECTED)) {
                /* Ensure that if we're calling a protected function, we're allowed to do so.
                 */
-               if (!zend_check_protected(fbc->common.scope, EG(scope))) {
+               if (!zend_check_protected(zend_get_function_root_class(fbc), EG(scope))) {
                        zend_error(E_ERROR, "Call to %s method %v::%v() from context '%v'", zend_visibility_string(fbc->common.fn_flags), ZEND_FN_SCOPE_NAME(fbc), method_name, EG(scope) ? EG(scope)->name : EMPTY_ZSTR);
                }
        }
@@ -846,7 +852,7 @@ ZEND_API zend_function *zend_std_get_static_method(zend_class_entry *ce, zstr fu
        } else if ((fbc->common.fn_flags & ZEND_ACC_PROTECTED)) {
                /* Ensure that if we're calling a protected function, we're allowed to do so.
                 */
-               if (!zend_check_protected(EG(scope), fbc->common.scope)) {
+               if (!zend_check_protected(zend_get_function_root_class(fbc), EG(scope))) {
                        zend_error(E_ERROR, "Call to %s method %v::%v() from context '%v'", zend_visibility_string(fbc->common.fn_flags), ZEND_FN_SCOPE_NAME(fbc), fbc->common.function_name, EG(scope) ? EG(scope)->name : EMPTY_ZSTR);
                }
        }
@@ -921,8 +927,10 @@ static union _zend_function *zend_std_get_constructor(zval *object TSRMLS_DC)
                        }
                } else if ((constructor->common.fn_flags & ZEND_ACC_PROTECTED)) {
                        /* Ensure that if we're calling a protected function, we're allowed to do so.
+                        * Constructors only have prototype if they are defined by an interface but
+                        * it is the compilers responsibility to take care of the prototype.
                         */
-                       if (!zend_check_protected(constructor->common.scope, EG(scope))) {
+                       if (!zend_check_protected(zend_get_function_root_class(constructor), EG(scope))) {
                                zend_error(E_ERROR, "Call to protected %v::%v() from context '%v'", constructor->common.scope->name, constructor->common.function_name, EG(scope) ? EG(scope)->name : EMPTY_ZSTR);
                        }
                }