【问题标题】:Why can child override and access its parent private method?为什么孩子可以覆盖并访问其父私有方法?
【发布时间】:2019-12-11 02:28:12
【问题描述】:

我习惯将方法作为protected 放在我的PHP 类中。但是玩private 我开始怀疑了。

我知道它可能是重复的,但我无法从我读过的 SO-answers 中找到清晰的答案。 检查了documentationSO answers,但我的测试仍然与那里所说的不一致(见下文)。

尤其是在 PHP 上下文中扩展相同类型类时,publicprivate 方法之间的那种“纠缠”并不常见。

例如:

<?php

class A
{
    private function ab() { echo 'test'.PHP_EOL; }
    public function test() { $this->ab(); }
    public function accessprivate($obj)  { $obj->ab(); }
}

class B extends A
{
        public function ab() { echo 'overridden-public'.PHP_EOL; }  // expect notice overriding private parent method
}

$a = new A;
$a2 = new A;
$b = new B;

$a->test(); // expect 'test'
$b->test(); // expect access to B::ab() and print 'overridden-public'
$b->ab();   // expect access to B::ab() and print 'overridden-public'
$a2->accessprivate($a); // expect 'test' since is the same class
$b->accessprivate($a); // expect cannotaccess private of A from class B

运行结果如下:

test test overridden-public test test

主要的一点是我希望private 方法被继承,但子类无法访问;因此:

  • 我应该无法将ab() 的可见性更改为public
  • B 中覆盖ab() 我希望test()$this 上调用ab() 作为B 实例,并打印“overridden-public”
  • accessprivate() from $a2 on $a 很好,因为它们是同一类
  • accessprivate() from $b on $a 应该不行,因为它们是不同的类(父母和孩子)

所以问题是:

  • 为什么我错了?我误会了什么?
  • 这种可见性模型在其他语言上是否相同,或者 PHP 的做法不同?在这种情况下,我的期望是否更适合其他语言的可见性模型?

【问题讨论】:

  • 您在问题中显示了预期结果,而不是实际结果。添加它们可能会有所帮助。
  • 已添加。谢谢你的建议????
  • 好问题。确实很奇葩。旁注:如果您创建一个类 C 并在其上定义 public function accessprivate($obj) { $obj-&gt;ab(); },您会得到预期的错误。我假设当您执行$obj-&gt;ab() 时,php 的上下文仍然绑定到 A,但我不知道为什么。
  • 其他旁注:您在B 上的public function ab() 没有覆盖任何内容。它在B 上创建了一个全新的方法。 (其他语言需要 override 关键字。Php 缺少此关键字,因此这可能会造成混淆。)拥有 A::ab() 私有因此禁止在 B 中调用其父调用,因此由于私有访问,您不能在 B 内执行 parent::ab() .

标签: php oop overriding visibility private-methods


【解决方案1】:

我应该无法将 ab() 的可见性更改为 public

重写实现必须具有相同的或更高可见性,以免违反LSP。覆盖的实现不会暴露父实现,所以这里没有根本问题。如果父级的实现是非公开的,那么无论出于何种目的和目的,它都不存在。出于所有意图和目的,孩子正在向类添加一个新方法,这很好。

B 中覆盖ab() 我希望test()$this 上调用ab() 作为B 实例,并打印“overridden-public”

private 方法是“硬绑定”到声明类的。 A::test 最好调用 private A::ab。这是专门为了类内部可以保留private。如果扩展类在不知不觉中实现了相同的方法,A 中的行为也就不足为奇了。

$b 上的$a 上的accessprivate() 不应该很好,因为它们是不同的类(父级和子级)

它仍然在调用A::accessprivate,因为B 没有实现任何这样的方法,而是与test 方法和上一段中的解释相同。

private 的目的主要是保证不受外部干扰或扩展代码。如果您将方法标记为private,则可以非常确定将调用哪个代码实现(始终是声明类),而不管子方法是否被覆盖。如果您牢记这一点,则该行为是非常符合预期且不言自明的。 protected 方法明确允许并期望覆盖发生并相应地表现。

【讨论】:

  • 嗯,还在处理中;但它开始变得有意义了,谢谢——不过,这很棘手,因为这看起来像是一种隐含的行为,而我宁愿希望得到一个通知,以防我在做我不允许做的事情去做(或者这不会产生任何影响,比如我的例子的非工作覆盖)。关于这个问题,PHP 文档似乎不太清楚。这种行为是否在 php.net 上的任何地方明确记录/提及?
猜你喜欢
  • 2012-03-20
  • 2014-11-03
  • 1970-01-01
  • 2021-05-18
  • 1970-01-01
  • 2023-03-14
  • 2016-12-23
  • 2011-04-30
  • 2018-07-08
相关资源
最近更新 更多