来自兄弟的受保护字段访问


Protected fields access from brother

我揭示了php>= 5.2的迭代行为

class A {
    protected $a = 'A';
    public function __get($f){ return 'field_'.$f; }
}
class B extends A {}
class C extends A {
    public function foo() {
        $b = new B();
        echo $b->a;
    }
}
$c = new C();
$c->foo();

我希望它打印field_a,但它打印A.
也。如果我从A中删除魔法 - 我预计会出现致命错误,但它仍然以 php>=5.2 打印A.

如果我们覆盖B::$a我们会得到另一种行为 - fatal error .

为什么?
是功能还是错误?

小提琴:
- http://3v4l.org/tiOC5 - 获取外国领域
- http://3v4l.org/uT9PC - 得到致命错误

这是因为 PHP 关于谁可以访问和不能访问类属性的非常时髦的规则。

在这里阅读:

http://php.net/manual/en/language.oop5.visibility.php

关键部分是这样的:

属性或方法的可见性可以通过前缀 带有关键字"公共"、"受保护"或"私有"的声明。类 宣布为公开的成员可以在任何地方访问。宣布的成员 受保护只能在类本身内访问,并且由 继承类和父类。被宣布为私人会员只能是 由定义成员的类访问。

强调我的。您可以访问从您继承的同一类继承的任何对象的受保护变量,即使是在另一个对象上也是如此。这还包括访问完全相同类的其他对象的私有属性。

这是一个好主意还是一个奇怪的功能还有待商榷,但它似乎是有意为之的。

我相信

如果你声明一个变量,它不会使用__get魔术方法。

因此,通过声明protected $a = 'A';,您将a排除在__get循环之外。它将跳过魔术方法,直接进入实际属性。

如果您查看魔术方法 __get() 和 __set() 的文档,您会发现它们仅在读取/写入无法访问的字段的情况下运行。

在您的示例中,$a可以从class C访问,因为它被定义为受保护的字段(继承/父类可以查看受保护的字段/方法)。如果将$a更改为私有字段,则应为示例调用魔术方法。