继承与调用(重新绑定)

讨论这个问题基于这么一个场景的。
class A {
     public function foo1() {
          echo "AAAAA";
     }
 
     public function foo2() {
          $this->foo1();
     }
}
 
class B {
     public function  foo1() {
          echo "BBBBB";
     }
}
 
$obj = new B();
$obj->foo2();
 
现在问题是,输出"AAAAAA",还是"BBBBBB"?
我们不急着去猜。先理清楚这几个方法。
先看父类,父类有一个foo1(),有一个foo2(),foo2()调用父类自己的foo1()。如果单看父类,这是很和谐的。
再看子类,子类从父类继承了foo2(),也继承了foo1(),然后把foo1()重写了一遍。按理说,由于没重写,子类$obj->foo2()调用的还是父类的foo2(),那么foo2()里面的$this->foo1()也是父类的foo1()吧?
 
很遗憾,错了,foo2()里面的$this->foo1()是子类的。输出结果是“BBBBB”。因为....重新绑定了。这就是这篇文章的主题。
 
什么叫动态(重新)绑定呢?引用java的的思路:
 
子类调用父类继承下来的方法($obj->foo2()),在该方法中用$this指向了父类的某个资源(foo2()中$this->foo1()),如果这个资源没被重写,那么该方法中$this指向的是父类资源($this->foo1()的foo1()是父类定义的)。如果这个资源被重写了(子类中重新定义了foo1()),那么该方法中$this指向的是子类资源($this->foo1()是子类的)。
 
条件:继承,用$this->调用(this是父类引用),资源重写,还要补充一个:子类调用父类的方法,像上面的$obj->foo2()。如果子类连foo2()都重写了,          
          那情况也很简单,foo2()里面的this肯定调用子类自己本身的资源。现在讨论的问题是父类方法调用资源问题,不是子类方法调用资源。
 
重写:能继承下来,重新定义。不能继承下来的,或者没重写的,一概不算重写。(像上面,如果父类的foo1是私有,没继承下来,子类的foo1不算重     
          写,那么动态绑定不成立,父类foo2指向的还是父类自己的foo1)
 
原则:父类对子类的东西是未知的,不能想着要调用子类的任何东西。而子类对父类的认知只有能能继承下来的东西。
 
设计原则(记住):
父类的public , private, protected该如何分配:
1、如果父类的方法需要被子类重写,那么就不要在父类写实现,抽象出来。属性没必要重写。(用protected,可以继承下去,然后重写嘛,重绑定)
2、父类什么时候用private呢?如果该资源只打算被父类的方法访问(这个方法可以继承下去),不打算被子类方法($this)访问,那么就不需要继承下去
     了,用private给父类内部用。方法一般用这个也比较多。
3、父类什么时候用protected呢?如果该资源打算给父类方法用,而且,又打算给子类方法用($this),但子类实例化不可以直接访问,那么就用protected
     继承下去吧。保险些,属性一般用这个。方法就少点。
4、父类什么时候用public呢?如果像让子类对象直接在外部访问。通常是不重写的供外部直接调用的方法,比较多。
 
如果没重写,所以把所有东西继承下去其实也不会出什么乱子,因为指向的都是父类的资源,没重新绑定。
 
如果有耐心的话可以看看以下的论证例子:
<?php
class A {
     protected $x =1;
     private $y = 2;
     public $z =3;
 
     public function getY() {
          echo 'this is A getY <br>';
          return $this->y;
     }
 
     public function getZ() {
          echo 'this is A getZ <br>';
          return $this->z;
     }
 
     public function getX() {
          echo 'this is A getX <br>';
          return $this->x;
     }
}
 
/**
class B extends A {
     //$x继承下来
     //$z继承下来
     //所有方法继承下来
     public function exe() {
          echo $this->getX();               //调用A的get父类的x
          echo '<br>';
          echo $this->getY();               //调用A的get父类的y
          echo '<br>';
          echo $this->getZ();               //调用A的get父类的z
          echo '<br>';
     }
}
/**
resutle
this is A getX
1
this is A getY
2
this is A getZ
3
**/
 
/**
class B extends A {
     //$x继承下来
     //$z继承下来
     //所有方法继承下来
     public $x = 10;                    //继承下来,内存空间不变,覆盖了,父类方法也是调用这个
     public $y = 20;                    //没继承下来,内存空间增加,没覆盖,有两个,父类方法不调用这个,调用父类的$y
     public $z = 30;                    //继承下来,内存空间不变,覆盖了,父类方法也是调用这个
 
     public function exe() {
          echo $this->getX();               //调用A的get子类的x               //方法继承了下来,要设置的成员也继承了下来
          echo '<br>';
          echo $this->getY();               //调用A的get父类的y               //方法继承法了下来,要设置的成员没有继承下来
          echo '<br>';
          echo $this->getZ();               //调用A的get子类的z               //方法继承了下来,要设置的成员也继承了下来
          echo '<br>';
     }
}
/**
result
this is A getX
10
this is A getY
2
this is A getZ
30
**/
 
/**
class B extends A {
     //$x继承下来
     //$z继承下来
     //所有方法继承下来
 
     public function exe() {
          echo $this->getX();                         //调用B中重写的getX(),x能继承下来,可以调用
          echo '<br>';
          echo $this->getY();                         //调用B中重写的getY(),y不能继承下来,不能调用,说在B中找不到资源
          echo '<br>';
          echo $this->getZ();                         //调用B中重写的getZ(),x能继承下来,可以调用
          echo '<br>';
     }
 
     public function getY() {
          echo 'this is B getY <br>';
          return $this->y;
     }
 
     public function getZ() {
          echo 'this is B getZ <br>';
          return $this->z;
     }
 
     public function getX() {
          echo 'this is B getX <br>';
          return $this->x;
     }
}
/**
this is B getX
1
this is B getY
Notice: Undefined property: B::$y
this is B getZ
3
**/
 
class B extends A {
     //$x继承下来
     //$z继承下来
     //所有方法继承下来
     public $x = 10;
     public $y = 20;
     public $z = 30;
 
     public function exe() {
          echo $this->getX();                         //调用B中重写的getX(),x能继承下来,一个储存空间,重写,调用重写后的x
          echo '<br>';
          echo $this->getY();                         //调用B中重写的getY(),y不能继承下来,两个储存空间,调用在B定义的y
          echo '<br>';
          echo $this->getZ();                         //调用B中重写的getZ(),x能继承下来, 一个储存空间,重写,调用重写后的z
          echo '<br>';
     }
 
     public function getY() {
          echo 'this is B getY <br>';
          return $this->y;
     }
 
     public function getZ() {
          echo 'this is B getZ <br>';
          return $this->z;
     }
 
     public function getX() {
          echo 'this is B getX <br>';
          return $this->x;
     }
}
/**
result
this is B getX
10
this is B getY
20
this is B getZ
30
**/
 
$objb = new B();
$objb->exe();
?>

posted on 2013-03-13 11:16  bgwan  阅读(199)  评论(0编辑  收藏  举报

导航