Подтвердить что ты не робот

Наследование PHP и видимость защищенного элемента

Я нашел кое-что, что кажется странной проблемой наследования в PHP.

Из руководства по PHP:

Объявленные защищенные члены могут быть доступны только внутри класса сам по себе и по унаследованным и родительским классам.

Для меня это означает: A может получить доступ к защищенным членам B, если A instanceof B или B instanceof A.

Однако, если оба A и B расширяют Foo, а Foo имеет защищенный конструктор, который не перезаписывается в B, то я могу создать экземпляр B изнутри A. Это не имеет смысла для меня, потому что A не является экземпляр B и B не является экземпляром A. Я также могу вызвать защищенный метод $b->test() изнутри A, который выполняет метод, реализованный в B. (Если B не обновляет test(), то реализация в Foo является выполненный.) Мне это еще более странно, потому что я не могу создать экземпляр B из A, если B непосредственно реализует защищенный конструктор. Кажется странным, что я не могу получить доступ к защищенному конструктору (также объявленному в родительском классе), но доступ к защищенному методу (также объявленному в родительском классе) не представляет проблемы.

Обратите внимание, что я получаю ожидаемое поведение, когда я использую класс C, который не расширяет Foo. Если я пытаюсь создать экземпляр B из C, я получаю фатальную ошибку, потому что я пытаюсь получить доступ к защищенному конструктору. Если я добавлю публичный конструктор в B, возможно его создать (что ожидается), и я до сих пор не могу получить доступ к защищенному методу test() (это также ожидаемое поведение). Я ожидаю такого же поведения при использовании A вместо C.

Пример кода, который снова объясняется:

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();

Я, вероятно, ничего не вижу, но я не могу найти что. Может ли кто-нибудь объяснить мне поведение?

4b9b3361

Ответ 1

Вы можете получить доступ к этим методам, потому что есть объявление их как защищенных в Foo, которое является вашим родителем и которое дает вам разрешение на доступ к нему. Если вы удалите объявление из родителя и объявите защищенный метод в B, вы получите Fatal Error.

Об этом сообщается как ошибка в PHP https://bugs.php.net/bug.php?id=50892