PHP面向對象:延遲靜態綁定(static關鍵字)

最近看到了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。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章