从兄弟访问受保护的字段

时间:2015-03-10 07:47:25

标签: php inheritance

我揭示了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移除魔法 - 我预计会发生致命错误,但仍会在A中打印php>=5.2

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

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

小提琴:
  - http://3v4l.org/tiOC5 - 获取外地字段
  - http://3v4l.org/uT9PC - 致命错误

3 个答案:

答案 0 :(得分:2)

这是因为PHP能够和不能访问类属性的非常时髦的规则。

在这里阅读:

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

关键部分是:

  

可以通过为前缀添加前缀来定义属性或方法的可见性   声明与关键字public,protected或private。类   公开的成员可以随处访问。 成员宣布   protected只能在类本身内部访问   继承和父类。声明为私有的成员可能只是   由定义成员的类访问。

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

这是一个好主意还是一个奇怪的功能是有争议的,但似乎是有意的。

答案 1 :(得分:1)

我相信如果你声明一个变量,它就不会使用__get魔法。

因此,通过声明protected $a = 'A';,您将从a周期中排除__get。它将跳过魔法并直接进入实际属性。

答案 2 :(得分:0)

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

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