Dziedziczenie PHP i widoczność chronionych elementów
Znalazłem coś, co wydaje się być dziwnym problemem dziedziczenia w PHP.
Dostęp do członków zadeklarowanych jako chronionych można uzyskać tylko w obrębie samej klasy oraz klas dziedziczonych i nadrzędnych.
Dla mnie oznacza to: A może uzyskać dostęp do chronionych członków B, jeśliA instanceof B
lubB instanceof A
.
Jeśli jednak zarówno A, jak i B rozszerzają Foo, a Foo ma chroniony konstruktor, który nie jest nadpisywany w B, to mogę utworzyć instancję B z poziomu A. To nie ma dla mnie sensu, ponieważ A nie jest instancją B i B nie są przypadkiem A. Mogę także nazwać metodę chronioną$b->test()
z poziomu A, który wykonuje metodę zaimplementowaną w B. (Jeśli B nie zmienia koloru na czerwony)test()
następnie wykonywana jest implementacja w Foo.) Dla mnie jest to jeszcze bardziej dziwne, ponieważ nie mogę utworzyć instancji B z poziomu A, jeśli B bezpośrednio implementuje chroniony konstruktor. Wydaje się dziwne, że nie mogę uzyskać dostępu do chronionego konstruktora (zadeklarowanego również w klasie nadrzędnej), ale dostęp do metody chronionej (zadeklarowanej również w klasie nadrzędnej) nie stanowi problemu.
Zauważ, że otrzymuję oczekiwane zachowanie, gdy używam klasy C, która nie rozszerza Foo. Jeśli spróbuję utworzyć instancję B z poziomu C, otrzymuję błąd krytyczny, ponieważ próbuję uzyskać dostęp do chronionego konstruktora. Jeśli dodam publiczny konstruktor do B, możliwe jest utworzenie jego instancji (co jest oczekiwane) i nadal nie mogę uzyskać dostępu do chronionej metodytest()
(jest to również oczekiwane zachowanie). Spodziewam się tego samego zachowania podczas używania A zamiast C.
Przykładowy kod, który ponownie wyjaśnia:
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();
Prawdopodobnie czegoś nie widzę, ale nie mogę znaleźć tego. Czy ktoś mógłby mi to wyjaśnić?