Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 415
Arjan Avatar asked Oct 05 '12 11:10

Arjan


People also ask

Can protected members be inherited in PHP?

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

How do I access protected members in PHP?

We can use bind() or bindTo methods of Closure class to access private/protected data of some class, for example: class MyClass { protected $variable = 'I am protected variable!

What is difference between public/private and protected in PHP?

public - the property or method can be accessed from everywhere. This is default. protected - the property or method can be accessed within the class and by classes derived from that class. private - the property or method can ONLY be accessed within the class.

What is different types of visibility in PHP?

PHP has three visibility keywords - public, private and protected. A class member declared with public keyword is accessible from anywhare. A protected member is accessible from within its class and by inheriting class.


1 Answers

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

like image 159
fd8s0 Avatar answered Oct 15 '22 19:10

fd8s0