奇怪的PHP行为,Base和Derived类的相同字段名称,克隆实例

抱歉这个混乱的 Headers ,我找不到更好的 Headers . 我在PHP / 5.6.14上,我有这个代码:

class Base
{
    private $foo;  <--- NOTE
    public function __construct()
    {
        $this->foo = "base foo";
    }
    public final function getFoo()
    {
        return $this->foo;
    }
}

class Derived extends Base
{
    public $foo;  <--- NOTE
    public function __construct($type)
    {
        parent::__construct();
        $this->foo = "derived foo";
        $this->somethingUndefined = "dynamically declared";  <--- NOTE
    }
}

$base = new Base();
var_dump($base->getFoo());
$derived = new Derived(0);
var_dump($derived->getFoo());
$clonedDerived = clone $derived;  <--- NOTE
var_dump($clonedDerived->getFoo());

运行最后 getFoo() 给了我:

PHP注意:未定义的属性:派生:: $ foo在C:.. \ test.php中的行在基类中实现getFoo()的行 .

如果我将这三个条件放在一起,我会收到通知:

  • 相同的公共/私人字段名称

  • 在派生类中有一个或多个动态声明的字段

  • 处理派生类实例的克隆

删除其中一个或多个会使通知消失 .

这里发生了什么? $foo 不是静态的,它使用自定义error_handler将每个E_ALL变为异常并且不能真正忽略这个...

EDIT :这只是我为重现问题而编写的一个例子,实际代码有很大不同 . 我只是想了解为什么,因为AFAIK它应该是完全没问题的 .

回答(2)

2 years ago

我相信这是PHP中的一个错误,因为在PHP7中运行该示例不会产生此通知 . 更重要的是,如果 getFoo() 定义中的 var_dump($this) ,则可以清楚地看到 "foo":"Base":private 被定义,并且对象 Derivedfoo 也被定义,在PHP> = 7和PHP <7中 . 请参阅:https://3v4l.org/Ob9m7

但是,我相信,无论你试图用这段代码做什么,你都会采用错误的方式 . 正如ArtisticPhoenix已经提到的那样 . 我强烈建议你重新考虑并重新设计你正在做的事情 . 根据OOP,覆盖私有成员是不可能的 .

2 years ago

这是预期的行为,私有只意味着这个类 . 因此,子类不可见私有属性 $foo . 将其更改为公开是不可行的,可能会有与您没有看到的相关的警告 . 报告给您的级别错误 .

子类必须至少保持父级的相同可见性 .

充其量你可以在子类中私有化,但这不会让你访问相同的 $foo

注意与否,当试图强制私有变量成为别的东西时,代码的可读性很差 . 你期望得到哪个foo?如果您在父级中需要 $foo 作为默认值,为什么不在其他名称中命名它,只需在子级的get方法中执行if / then .

基本上你试图在子类中更改 $foo 的值,当它在父类中是私有的时 . 然后从父级中检索它 . 正如我最多提到的那样,你不会得到你期望的 $foo ,这会使代码混乱 .