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 版的解释。
这是不是覆盖不覆盖的问题,而是因为所使用的属性访问控制为private,getVar()方法就直接会找本类的属性,不会去检查继承链。
同样的,父类中访问控制为private的方法,如果通过其他父类的方法调用,即使在子类中也存在同名的方法,调用的方法也会使用父类原来的方法,不会管子类中的方法。
说简单点,private是不存在继承这么一说的。