Reputation: 9884
I've found something that appears to be a strange inheritance issue in PHP.
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
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
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