Arjan
Arjan

Reputation: 9884

PHP inheritance and protected member visibility

I've found something that appears to be a strange inheritance issue in PHP.

From the PHP manual:

Members declared protected can be accessed only within the class itself and by inherited and parent classes.

To me this means: A can access the protected members of B if A instanceof B or B instanceof A.

However, if both A and B extend Foo, and Foo has a protected constructor which is not overwritten in B, then I can create an instance of B from within A. This does not make sense to me, because A is not an instance of B and B is not an instance of A. I can also call the protected method $b->test() from within A, which executes the method implemented in B. (If B does not redeclare test() then the implementation in Foo is executed.) To me this is even more strange because I cannot create an instance of B from within A if B directly implements a protected constructor. It seems strange that I cannot access a protected constructor (also declared in the parent class) but accessing a protected method (also declared in the parent class) is no problem.

Note that I do get the expected behavior when I use a class C which does not extend Foo. If I try to instantiate B from within C, I get a fatal error because I'm trying to access a protected constructor. If I add a public constructor to B it is possible to instantiate it (which is expected) and I still cannot access the protected method test() (this is also expected behavior). I expect the same behavior when using A instead of C.

Sample code which explains again:

class Foo {
    protected function __construct() {
        echo('Constructing ' . get_called_class());
    }

    protected function test() {
        echo('Hello world ' . __METHOD__);
    }
}

class A extends Foo {
    public function __construct() {
        parent::__construct();
    }

    public function testB() {
        // Both of these lines work
        $b = new B();
        $b->test();
    }
}

class B extends Foo {
    protected function test() {
        echo('Hello world Again ' . __METHOD__);
    }
}

class C {
    public function __construct() {
    }

    public function testB() {
        // Both of these lines cause fatal errors
        $b = new B();
        $b->test();
    }
}

$a = new A();
$a->testB();

$c = new C();
$c->testB();

I'm probably not seeing something, but I can't find what. Could anyone explain the behavior to me?

Upvotes: 14

Views: 3473

Answers (2)

Newbo.O
Newbo.O

Reputation: 1948

There is no rationale about this, it has been reported 2 years ago: https://bugs.php.net/bug.php?id=52120

Upvotes: 1

fd8s0
fd8s0

Reputation: 1927

You can access those methods because there is a declaration of them as protected in Foo, which is your parent and that gives you permission to access it. If you remove the declaration from the parent and declare the protected method in B you will get a Fatal Error.

This is reported as a bug in PHP https://bugs.php.net/bug.php?id=50892

Upvotes: 6

Related Questions