文章大纲

PHP父类方法里如何访问子类属性

2020-02-23 18:53:55

也许是一直在路上走得太匆忙,而忽视了道路两旁不起眼但点缀了风景的小花小草。


PHP中父类方法里如何访问子类属性?答案很简单,就是父类、子类里属性的权限修饰符都定义为protected就好了。


写了一小段代码进行实践确认的时候,无意间发现自己有些地方不太确定,遂对public,protected,private这块进行了补习。


下面是我的测试代码:

<?php
class P
{
    protected $attr = "CoderZhai";
    public function getFields(){
        echo get_class($this);
        return $this->attr;
    }
}

class C extends P
{
    protected $attr = "Hello World";
}

$obj = new C();
var_dump($obj->getFields());

下面是属性定义的所有可能性方式,如果你能说出以下所有情形的输出,那说明你这方面的基础知识还是很扎实的,可以不用看本文了。


PC
1private
private
2private
protected
3private
public
4protected
private
5protected
protected
6protected
public
7public
private
8public
protected
9public
public

为了描述方便和简洁,“权限修饰符”这几个字将会在大部分地方省略。

经过内心的拷问,发现自己对上面9种情况的结果有点不确定。实践过后,可以归纳成如下2个问题。

问题1:父类P里属性为protected,子类C里属性定义为private,结果会如何?(对应4、7、8情形)

答案:编辑器里会出现报错提示:Access level to C::$attr must be protected( as in class P) or weaker。说的就是子类C里同名属性权限必须要么是protected,要么是权限更放得开的public。

这跟php的语法要求有关:
子类里的属性访问权限必须大于或等于父类里的同名属性的权限


问题2:父类P里属性为private,子类C里属性定义为private\protected\public,属性结果始终是CoderZhai(对应1、2、3情形),但是将P类里属性权限修饰符改成protected\public,结果就是Hello World了(对应5、6、9情形)。

答案:有点特殊的就是父类P里属性为private时,$this指向的是子类C,可是$this->attr却调用的是P类的属性。此问题的具体实践分析过程,请继续看后文。


本文为翟码农个人博客蓝翟红尘里php分类下的原创文章,转载请注明出处:http://www.zhai14.com/blog/how-to-call-the-attributes-in-child-class-from-parent-class-in-php.html


下面是翟码农个人结合实践的理解,如有谬误,还望指正。


首先,让我们来熟悉下权限修饰符的描述。


public 公共的
无论是类里还是类外都可访问

protected 受保护的
protected修饰的成员,
可以在当前类或当前类的上下级具有继承关系的类中访问。

private 私有的
private修饰的成员,只能在其所在的类中访问。


接着在上面测试代码,加上如下一行代码,方便调试观察$this的全部内容。

echo get_class($this);
var_dump($this);  //查看$this详细内容
return $this->attr;


经测试,当P类attr属性为private时,无论子类C的属性是private\protected\public中哪一个,$this打印出来的都是含有两个属性值的。

object(C)[1]
  private 'attr' => string 'Hello World' (length=11)
  private 'attr' (P) => string 'CoderZhai' (length=9)


而当把父类P中attr属性改为protected\public时,子类C的同名属性attr赋值则会造成覆写,从而始终只会有一个属性,且属性值是子类C中给予的那个值。当父类P中attr属性为protected,子类C中attr属性为public时,$this打印结果如下:

object(C)[1]
  public 'attr' => string 'Hello World' (length=11)


由此可见:

当父类中属性为private时,继承于该父类的子类,创建的同名属性,无论什么权限修饰符,都相当于新建的属性,否则就是对父类属性的覆写(override)


对于C类只有一个属性的时候,$this->attr获取的结果毫无疑问。


现在就是当$this指向对象打印出来有两个属性时,即父类属性attr为private的时候,经过实践证明,此时无论$this指向哪个子类,$this->attr调用的都是父类P里的private attr属性。


如果一定要给一个理由,那就是“在哪个类里调用,哪个类的属性就优先”吧,这样子也方便记忆。

记忆诀窍:就近原则,代码在哪个类就优先调用哪个类的属性


不信?那就将getFields方法挪到子类C里面去,你们自己试试看吧。


我要评论
评论列表