PHP继承的问题,调用父类的方法this指向问题。
public function m(){
echo 'aa';
}
public function run(){
$this->m();
}
}
class b extends a{
public function m(){
echo 'bb';
}
}
$li = new b();
$li->run();
谁能跟我分析一下这为什么是访问的b类里面的m方法,如果把a类的m方法权限改为private,又为什么变成访问的是a类的m方法了。。
声明一个类的时候,如果这个类继承某个类,那么这父类的方法在子类中是如何体现的,完全复制一份吗? 展开
我来说一说:
【一】…………public(仅有)属性和方法的继承…………
class a{
public $var = 'var a <br/>';
public function m(){
echo 'fun a <br/>';
}
public function run(){
echo $this->var;
$this->m();
}
}
class b extends a{
public $var = 'var b <br/>';
public function m(){
echo 'fun b <br/>';
}
}
$li = new b();
$li->run();
echo '<hr>';
var_dump($li);
输出:
var b
fun b
————————————————————————————
object(b)[1]
public 'var' => string 'var b <br/>' (length=11)
在这段代码中所表示的,是我们常见的一种继承方式,同为公有属性的$var 和公有方法m()
在这里,$var和m()都被继承并覆写,实例化过后,内存中只有一个$var实例,通过var_dump($li);我们可以看到它。
【二】…………private(私有)属性和方法的继承…………
class a{
private $var = 'var a <br/>';
private function m(){
echo 'fun a <br/>';
}
public function run(){
echo $this->var;
$this->m();
var_dump($this);
echo '<br/><br/>';
}
}
class b extends a{
private $var = 'var b <br/>';
private function m(){
echo 'fun b <br/>';
}
public function run(){
echo $this->var;
$this->m();
var_dump($this);
echo '<br/><br/>';
parent::run();
}
}
$li = new b();
$li->run();
echo '<hr>';
var_dump($li);
输出:
var b
fun b
object(b)[1]
private 'var' => string 'var b <br/>' (length=11)
private 'var' (a) => string 'var a <br/>' (length=11)
.
.
var a
fun a
object(b)[1]
private 'var' => string 'var b <br/>' (length=11)
private 'var' (a) => string 'var a <br/>' (length=11)
.
————————————————————————————————
object(b)[1]
private 'var' => string 'var b <br/>' (length=11)
private 'var' (a) => string 'var a <br/>' (length=11)
这个时候,我们可以看到,在调用run方法时,首先它会调用到b类的私有属性$var 和私有方法m(),随后,又使用parent::run()调用父类的run()方法,我们可以看到,父类的run()方法调用后,它所调用的属性和方法,都是a类的两个私有属性和方法,这种形式,和你的问题一致;
而它与$this指向无关,我们可以在这里看到,两个$this都是指向b类。
而最有意思的是,在$li句柄中,我们却看到了两个属性!一个是b类的属性,一个是a类的属性,这两个属性同时存在着,那么,私有方法也自然是同时存在着。
【三】…………私有属性和方法能不能被继承…………
class a{
private $var = 'var a <br/>';
private function m(){
echo 'fun a <br/>';
}
}
class b extends a{
public function run(){
echo $this->var;
$this->m();
}
}
$li = new b();
$li->run();
输出:
Notice: Undefined property: b::$var in E: ... on Line 9
Fatal error: Call to private method a::m() from context 'b' in E: ... on Line 10
这可以证明,私有属性和方法,无法被继承,所以,你的代码示例中所说,将a类的m()方法更改为private后,会显示aa的属性,也就可以理解明白了。
将a类的m()方法更改为private后,会显示aa的属性 还是无法理解,虽然没有继承过去,但其子类b也是调动个m方法,而它与$this指向无关,我们可以在这里看到,两个$this都是指向b类。你这里说这this指向的是b。那应该还是调用b类的m方法才对的啊
“将a类的m()方法更改为private后,会显示aa的属性”这句话是我打字太顺了手,出了差错,没有最后“的属性”三字,是:“将a类的m()方法更改为private后,会显示aa”
它确实是与$this的指向无关的,但却与$this的位置有关系。
私有的属性和方法,只能够在该类中被调用,像你的这个程序中,没有属性,只有方法,而run()方法虽然被继承到了b类中,但它仍然属于a类的方法,并不是b类的,所以,它里面的$this->m()自然就是a类中私有的方法m(),而非b类中“新定义”的公有方法m(),这就是说,内存中实际上是有两个m()方法的,一个属于a类,一个属于b类,两个毫不相关,各是各的。
当你调用继承自a类的方法run()时,run()方法中的$this,这个$this位于a类之中,隶属于a类,所以a类中的私有方法m()是对其开放的,然后我们再看,如果这个$this出现在b类中,那这个时候,这个b类中的$this->m(),指向的就不再是a类的私有方法m()了,而是b类中“新定义的”的m()。
为什么说是“新定义”?因为a类中的m()方法是私有的,无法继承嘛,所以b类的m()方法是“新定义”的。
这里面有一个弯,你反过来再想想,对于a类来说,a类里的run()函数是不是属于a类的?是吧?
那么,在run()方法中使用$this,还无法访问它里面的私有属性,却是跑到其它地方去访问一个“新定义”的一个新方法,这才叫奇怪不是?
所以,这个现象是正常的,而我们却是以“为什么我把public改为private,它就变了呢?”这个先入为主的思想给误导了。
不知道你有没有理解?
第二次输出的是a类的方法那,是不是说明 这$this->m();这里的this指向的是a类,不是指向b这个子类,那为什么第一次的this指向的是b这个子类呢??方法被重写了,那不代表父类的这个方法不存在了吧?要访问父类的方法还是可以访问的。
public时,实例化b类,方法m被重写,那么内存中应该是只有一个方法m,而不会有两个m方法,所以只会输出b类里m方法的结果。这个可以明白吧。
而第二次private时,内存中就两个m函数,那自然就是访问自己的私有属性m函数了,即a类的m方法
参考:http://cn2.php.net/manual/zh/language.oop5.inheritance.php
class A
{
public function get()
{
return "something";
}
}
class B extends A
{
public function get()
{
// 不能用$this->get()调用自己,否则死循环递归了
return parent::get() . " and others";
}
}