最近看到了PHP面向對象中的延遲靜態綁定這塊,注意:php5.3之前沒有引入延遲靜態綁定,所以版本較低的童鞋可能用不了。
這裏我們用一個簡單的工廠方法(生成包含類的實例的一種方法)來說明
//定義一個抽象方法作爲父類abstract class ParentClass{ //....}//子類Userclass User extends ParentClass{ //定義一個靜態方法來生成返回一個類實例 public static function create(){ return new User(); } }//子類Animalclass Animal extends ParentClass{ public static function create(){ return new Animal(); } }//使用:print_r(User::create()); print_r(Animal::create()); //返回:User Object ( ) Animal Object ( )12345678910111213141516171819202122232425
從返回結果上看,我們取得了兩個子類的實例,說明這個工廠方法正常的工作了。但是,假如我假如Document、Plant等子類呢?我們要重寫很多create()方法!這個很煩人!既然create()方法都是類似的,我把這個方法放到父類中怎麼樣?
abstract class ParentClass{ //定義一個靜態方法來生成返回一個類實例 public static function create(){ return new self(); } }//子類Userclass User extends ParentClass{ //...}//子類Animalclass Animal extends ParentClass{ //...}//使用:print_r(User::create()); print_r(Animal::create()); //返回:Fatal error: Cannot instantiate abstract class ParentClass in....123456789101112131415161718192021
返回的結果:不能實例化ParentClass這個抽象類!
好,我們把抽象abstract去掉:
class ParentClass{ //定義一個靜態方法來生成返回一個類實例 public static function create(){ return new self(); } }//返回結果:ParentClass Object ( ) ParentClass Object ( )123456789
去掉abstract前後都足以證明:self()調用的是基類本身。
也就不能把create()放在父類中?錯!
PHP5.3之後引入了延遲靜態綁定的概念。該特性最明顯的標誌就是新關鍵字static(靜態)。static類似於self,但它表示的是被調用的類而不是包含類。現在我們用 static() 替換 self() :
abstract class ParentClass{ //定義一個靜態方法來生成返回一個類實例 public static function create(){ return new static(); } }//子類Userclass User extends ParentClass{ //...}//子類Animalclass Animal extends ParentClass{ //...}//使用:print_r(User::create()); print_r(Animal::create()); //返回:User Object ( ) Animal Object ( )12345678910111213141516171819202122
我們暫時可以這樣理解:self()只能父類中起作用,只會緊跟在所在類中,固定的,而static()靈活性更強,誰調用我,我就是在誰那裏起作用,被子類繼承下來,那就是指的是子類。在本類中,self()指的是ParentClass,而對於static(),子類User調用我,我就是指User類。當然,通過ParentClass類的對象調用create(),static()指的就是ParentClass類了
關於static關鍵字,它不僅可以用於實例化所在類,和self和parent一樣,static還可以調用類裏面的方法:
//這裏先用selfclass ParentClass{ public $order; //構造函數 function __construct(){ $this->order = self::getOrder();//調用本類的getorder()方法 } //延遲靜態綁定 public static function create(){ return new static(); } public function getOrder(){ return "ParentClass"; } }class User extends ParentClass{ //重寫getOrder()方法 public function getOrder(){ return "User"; } }class Animal extends ParentClass{ //重寫getOrder()方法 public function getOrder(){ return "Animal"; } }//使用:print_r(User::create()); print_r(Animal::create());//返回結果:User Object ( [order] => ParentClass ) Animal Object ( [order] => ParentClass )123456789101112131415161718192021222324252627282930313233
結果也說明了,self關鍵字只能父類中起作用,只會緊跟在所在類中,
我們把self換成static:
class ParentClass{ public $order; //構造函數 function __construct(){ $this->order = static::getOrder();//調用本類的getorder()方法 } public static function create(){ return new static(); } public function getOrder(){ return "ParentClass"; } }//使用:print_r(User::create()); print_r(Animal::create());//返回結果:User Object ( [order] => User ) Animal Object ( [order] => Animal )1234567891011121314151617181920
看結果,static成功的調用了子類中的getOrder()方法!
現在我比較喜歡拿C#和PHP作對比。。。。
在這裏,我感覺這跟C#中的運行時多態比較相似(多態後面給大家介紹,這裏先用了)
//動物類:父類 public class Animal { public int age;//年齡 public double weight;//體重 //吃方法:虛方法 public virtual string Eat() { return "Animal Eat"; } public virtual string Sleep() { return "Animal Sleep"; } } //狗類:子類 public class Dog : Animal { //覆寫虛方法 public override string Eat() { return "Dog Eat"; } public override string Sleep() { return "Dog Sleep"; } } public class Bird : Animal { public override string Eat() { return "Bird Eat"; } public override string Sleep() { return "Bird Sleep"; } }//使用:Animal al1 = new Dog(); Animal al2 = new Bird(); Console.WriteLine(al1.Sleep()); Console.WriteLine(al2.Sleep()); Console.ReadLine();//輸出結果:Dog Sleep Bird Sleep12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
假如我把Dog類中的覆寫Sleep()方法去掉
public class Dog : Animal { //覆寫虛方法 public override string Eat() { return "Dog Eat"; } }//返回結果:Animal Sleep Bird Sleep123456789101112
運行時多態(virtual 和 override 關鍵字):當用子類實例化父類的時候,通過判斷對象的類型來決定執行哪個類中的哪個方法,在這裏:Animal al1 = new Dog();
al1的類型是Animal,然後去Animal類裏面找Sleep()方法,但是,當發現Sleep()方法是個虛方法,到Dog()裏面看看該方法有沒有被覆寫,假如被覆寫了,調用覆寫後的方法,不然調用虛方法。
這就好比PHP中的延遲靜態綁定中的 self 和 static 關鍵字,假如子類中有覆寫(override)父類的虛方法,就相當於使用 static,沒有覆寫就相當於使用 self。