Dziedziczenie PHP i widoczność chronionych elementów

Znalazłem coś, co wydaje się być dziwnym problemem dziedziczenia w PHP.

Z podręcznika 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ć?

questionAnswers(2)

yourAnswerToTheQuestion