【问题标题】:PHP inheritance and protected member visibilityPHP 继承和受保护的成员可见性
【发布时间】:2012-09-26 13:25:17
【问题描述】:

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

From the PHP manual

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

对我来说,这意味着: 如果A instanceof BB 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();

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

【问题讨论】:

  • 确实很奇怪的行为。
  • 您想要解释这种行为背后的基本原理或实现吗?由于这是 PHP,因此很有可能 没有理由。
  • 如果有理由,我想知道它是什么。
  • 如果在B 中添加受保护的构造函数,A::testB 将不起作用。所以我认为当 A::testB 尝试调用 B 构造函数时,它会尝试直接调用 Foo 构造函数(因为它在 B 中错过了)。 Foo::_constructor 可以从 A 访问,所以它可以工作(也许它没有子类的记忆)。我不在这里告诉它是对还是错......但我认为这发生了

标签: php inheritance


【解决方案1】:

这个没有道理,2年前就有报道了:https://bugs.php.net/bug.php?id=52120

【讨论】:

  • 感谢您的链接。我认为你可以调用继承的受保护方法比调用继承的构造函数更奇怪(这是预期的行为,imo)
【解决方案2】:

您可以访问这些方法,因为在 Foo 中声明它们受保护,这是您的父级,并授予您访问它的权限。如果您从父级中删除声明并在B 中声明受保护的方法,您将收到致命错误。

这被报告为 PHP https://bugs.php.net/bug.php?id=50892 中的一个错误

【讨论】:

  • 如果B 覆盖__construct,即使Foo 声明它,您也不能从A 调用new B()
  • 感谢您指向 bugs.php.net 链接。我在那里进行了搜索,但找不到错误报告。
猜你喜欢
  • 2016-06-12
  • 2014-06-09
  • 2013-03-20
  • 1970-01-01
  • 2023-03-23
  • 2016-02-29
  • 2018-12-27
  • 2012-10-03
  • 2023-03-03
相关资源
最近更新 更多