PHP是否可像Java一样访问被隐藏的实例字段?
Java vs PHP:父类实例字段的继承与访问差异
先从你提到的Java场景说起——在Java里,子类确实可以继承父类的实例字段,要是子类声明了同名的字段,父类的字段会被隐藏,这时候子类可以通过this访问自己的字段,用super访问父类被隐藏的字段。比如你给出的例子:
class Foo { protected int x = 1; } class Bar extends Foo { protected int x = 2; void somemethod() { System.out.println(this.x); // 输出2 System.out.println(super.x); // 输出1 } }
不过得强调一句:这种字段隐藏的写法是不良实践,很容易让代码逻辑混乱,咱们也就是学术探讨下哈。
PHP中能不能访问被“隐藏”的父类实例字段?
答案是:没法像Java那样直接通过类似super的关键字访问,因为PHP里子类声明同名字段的行为不是“隐藏”,而是覆盖(重定义)——子类的字段会直接覆盖父类的同名字段,子类实例里并不会同时存在父类和子类的两个$x字段。
你给出的PHP代码里,$parent->x肯定行不通,PHP根本没有$parent这个内置变量来指代父类实例。那有没有办法拿到父类原本的$x值呢?有两种方案,但都不是像Java那样直接的方式:
方案1:父类添加Getter方法(推荐)
最稳妥的方式是在父类里专门加一个方法,用来返回父类的字段值,子类通过parent::调用这个方法就能拿到父类的$x:
<?php class Foo { protected $x = 1; // 父类提供获取自身x的方法 protected function getParentX() { return $this->x; } } class Bar extends Foo { protected $x = 2; function somemethod() { echo $this->x, PHP_EOL; // 输出2 echo parent::getParentX(), PHP_EOL; // 输出1 } } $bar = new Bar(); $bar->somemethod();
方案2:使用反射(不推荐)
如果没办法修改父类代码,那可以用PHP的反射机制来强行获取父类的属性值,但这种方式比较hack,可读性差,除非万不得已不建议用:
<?php class Foo { protected $x = 1; } class Bar extends Foo { protected $x = 2; function somemethod() { echo $this->x, PHP_EOL; // 输出2 // 通过反射获取父类的x属性 $reflection = new ReflectionClass(parent::class); $property = $reflection->getProperty('x'); $property->setAccessible(true); // 让受保护的属性可访问 echo $property->getValue($this), PHP_EOL; // 输出1 } } $bar = new Bar(); $bar->somemethod();
总结一下
- Java中是字段隐藏:父类和子类的同名字段会同时存在于子类实例中,可通过
super访问父类的那个字段。 - PHP中是字段覆盖:子类的同名字段会直接替换父类的字段,子类实例里只有子类的那个字段,没法直接访问父类原本的值,只能通过父类Getter或者反射间接获取。
- 不管是Java还是PHP,这种子类和父类用同名字段的做法都不推荐,很容易搞混逻辑,尽量避免。
内容的提问来源于stack exchange,提问作者Malte Skoruppa
相关产品推荐
相关产品推荐

