我揭示了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
更改为私有字段,则应为示例调用魔术方法。