private 继承中的 $this 问题

LemonLone
  • 237
class base
{
    private $_var = 20;

    public function getVar()
    {
        echo $this->_var;
    }
}

class Ext extends base
{
    private $_var = 30;
}

$obj = new Ext();
$obj->getVar();

输出:20

之前提过一次这个问题:继承会拥有父类的 Private 属性和方法吗?,沙渺的回答也解答了疑惑,上面的代码也验证了这个解答。

但是,$this 的特性不是动态指定的吗?谁调用就指向谁,这里是 Ext 的对象调用的,虽然 getVar() 是基类的,但是按照 $this 的特性,不应该是指向 Ext 对象的吗?


2016-09-11 12:02,没人回答,试了下在基类中打印出 $this,分两种情况:

1、基类属性为 private

class base
{
    private $_var = 20;

    public function getVar()
    {
        var_dump($this);
        echo $this->_var;
    }
}

class Ext extends base
{
    protected $_var = 30;
}

$obj = new Ext();
$obj->getVar();

结果:

object(Ext)#1 (2) { ["_var":protected]=> int(30) ["_var":"base":private]=> int(20) } 20

2、基类的属性为 protected(也可以都为 public,总之希望被覆盖)

class base
{
    protected $_var = 20;

    public function getVar()
    {
        var_dump($this);
        echo $this->_var;
    }
}

class Ext extends base
{
    protected $_var = 30;
}

$obj = new Ext();
$obj->getVar();

结果:

object(Ext)#1 (1) { ["_var":protected]=> int(30) } 30

可以肯定的是:$this 确实指向的是 Ext 对象。

而之所以第二种情况输出了 30,看 dump 也很明显了,例子 2 中的 protected 属性被覆盖了,而 1 中的 private 得到了保留(private 默认是 final,无法被覆盖)。

所以这种现象是不是叫做“向上查找”(我自己杜撰的词)?因为 private 无法被覆盖,所以最终找到了父类的 var?

(事实上也没有合理的解释 $this 的问题)


2016-09-11 20:57

图片描述

图片描述

上面两图来自 Thinking in java,当创建子类时,与组合的显式创建不同,继承会隐含的在其内部创建一个基类对象。

这或许解释了 $this 的问题:

$this 是对 Ext 内存基址的引用,而此时基类的 Base 对象在其内部,再从 dump 出的结果,至少从表面上很好理解了,因为这个 $this 是写在 Base 对象中的,而 private 默认是 final 所以并不会被 override(dump 可以看到都得到了保留,Ext 中的 $_var 是个全新的属性)。

而当基类中的 $_var 为 protected / public 并且被子类覆盖时,不管“内含对象”的底层实现机制如何,至少从 dump 结果可以看到所谓的“覆盖”:基类的 $_var 已经不存在了,取而代之的是子类的 $_var,输出 30 也就很好理解了。

另外 stackoverflow 的同类问题:Behavior of $this on inherited methods
回答中提到的 “virtual method” 和 “lookup table” 概念也值得参考。


2016-09-12 20:34
JAVA 中this 和super与覆写冲突的问题?,甘明:java 版的解释。

回复
阅读 2.4k
1 个回答
有明
  • 26.6k

这是不是覆盖不覆盖的问题,而是因为所使用的属性访问控制为private,getVar()方法就直接会找本类的属性,不会去检查继承链。

同样的,父类中访问控制为private的方法,如果通过其他父类的方法调用,即使在子类中也存在同名的方法,调用的方法也会使用父类原来的方法,不会管子类中的方法。

说简单点,private是不存在继承这么一说的。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
宣传栏