我在PHP中遇到了一个看起来似乎是奇怪的继承问题。
声明为protected的成员只能被类本身、继承的子类和父类访问。
对我而言,这意味着:
如果 A instanceof B
或者 B instanceof A
,则 A 可以访问 B 的受保护成员。
然而,如果A和B都扩展自Foo,并且Foo有一个未被B覆盖的受保护构造函数,则我可以在A内部创建B的实例。这对我来说没有意义,因为A不是B的实例,B也不是A的实例。我还可以调用 $b->test()
这个受保护方法,在A中执行B中的方法实现。(如果B没有重新声明 test()
,那么会执行Foo中的实现。)对我来说,更奇怪的是,如果B直接实现了一个受保护的构造函数,则我无法从A中创建B的实例。这似乎很奇怪,因为我无法访问受保护的构造函数(也在父类中声明),但是访问受保护的方法(也在父类中声明)却没有问题。
请注意,当我使用一个不扩展Foo的类C时,我会得到预期的行为。如果我尝试从C中实例化B,则会出现致命错误,因为我正在尝试访问受保护的构造函数。如果我向B添加一个公共构造函数,则可以实例化它(这是预期的),但我仍然无法访问受保护的方法 test()
(这也是预期行为)。我期望使用A时会得到相同的行为。
以下是解释样例的代码:
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();
我可能看漏了什么,但是我找不到问题所在。有人能够解释一下这种行为吗?
B
中添加了一个受保护的构造函数,则A::testB将无法工作。因此,我认为当A::testB尝试调用B
构造函数时,它会直接调用Foo构造函数(因为它在B
中缺失)。Foo::_constructor可以从A访问,因此它可以工作(也许它没有子类的记忆)。我不在这里说明它是对还是错...但我认为会发生这种情况。 - Luca Rainone