PHP继承和受保护的成员可见性

PHP继承和受保护的成员可见性,php,inheritance,Php,Inheritance,我在PHP中发现了一个奇怪的继承问题 : 声明为受保护的成员只能在类内访问 本身以及继承的类和父类 对我来说,这意味着: 如果A instanceof B或B instanceof A,A可以访问B的受保护成员 但是,如果A和B都扩展了Foo,并且Foo有一个受保护的构造函数在B中没有被覆盖,那么我可以从A中创建B的实例。这对我来说没有意义,因为A不是B的实例,B也不是A的实例。我还可以从A中调用受保护的方法$B->test(),它执行在B中实现的方法。(如果B没有重新声明test(),那么执行

我在PHP中发现了一个奇怪的继承问题

:

声明为受保护的成员只能在类内访问 本身以及继承的类和父类

对我来说,这意味着: 如果
A instanceof B
B instanceof A
,A可以访问B的受保护成员

但是,如果A和B都扩展了Foo,并且Foo有一个受保护的构造函数在B中没有被覆盖,那么我可以从A中创建B的实例。这对我来说没有意义,因为A不是B的实例,B也不是A的实例。我还可以从A中调用受保护的方法
$B->test()
,它执行在B中实现的方法。(如果B没有重新声明
test()
,那么执行在Foo中的实现。)对我来说,这更奇怪,因为如果B直接实现受保护的构造函数,我无法从A中创建B的实例。奇怪的是,我无法访问受保护的构造函数(也在父类中声明),但访问受保护的方法(也在父类中声明)没有问题

注意,当我使用不扩展Foo的类C时,我确实得到了预期的行为。如果我试图从C中实例化B,我会得到一个致命错误,因为我试图访问一个受保护的构造函数。如果我向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();

我可能没看到什么,但我找不到什么。有人能向我解释一下这种行为吗?

您可以访问这些方法,因为在
Foo
中有一个声明将它们声明为受保护的,它是您的父对象,并授予您访问它的权限。如果从父级中删除声明并在
B
中声明受保护的方法,则会出现致命错误


这被称为PHP中的一个bug,这是没有道理的,两年前就有报道说:

确实是非常奇怪的行为。你想解释一下这种行为背后的原理还是实现?因为这是PHP,所以很有可能没有理由。如果有理由,我想知道它是什么。如果在
B
中添加受保护的构造函数,a::testB不起作用。所以我认为,当A::testB尝试调用
B
构造函数时,它会尝试直接调用Foo构造函数(因为它在
B
中遗漏了)。Foo::构造函数可以从访问,因此它可以工作(可能它没有子类的内存)。这里我不知道它是对还是错……但我认为这种情况会发生,如果
B
覆盖
\uu构造
,即使
Foo
声明了它,也不能从
A
调用
new B()
。感谢您将我指向bugs.php.net链接。我确实在那里搜索过,但是找不到bug报告。谢谢你的链接。我认为更奇怪的是,您可以调用继承的受保护方法,而不是调用继承的构造函数(这是预期行为,imo)