什麼是多態?
多態(Polymorphism)按字面的意思就是“多種狀態”。在面向對象語言中,接口的多種不同的實現方式即為多態。引用Charlie Calverts對多態的描述——多態性是允許你將父對象設置成為和一個或更多的他的子對象相等的技術,賦值之後,父對象就可以根據當前賦值給它的子對象的特性以不同的方式運作(摘自“Delphi4編程技術內幕”)。簡單的說,就是一句話:允許將子類類型的指針賦值給父類類型的指針(沒錯這段話來自百度百科)。那麼多態的作用是什麼,它有什麼實際開發價值呢?在實際的應用開發中,采用面向對象中的多態主要在於可以將不同的子類對象都當作一個父類來處理,並且可以屏蔽不同子類對象之間所存在的差異,寫出通用的代碼,做出通用的編程,以適應需求的不斷變化。
下面就是PHP中多態的兩個實現
重載是類的多態的一種實現。函數重載指一個標識符被用作多個函數名,且能夠通過函數的參數個數或參數類型將這些同名的函數區分開來,調用不發生混淆。即當調用的時候,雖然方法名字相同,但根據參數的不同可以自動調用相應的函數。
class A{ public function test(){ echo "test1"; } public function test($a){ echo "test2"; } } $a=new A(); $a->test(); $a->test($a);
假如php直接支持方法重載的話。那麼上面的例子執行後傳參和不傳參就會返回不同的值。然而php並不直接支持重載,這就意味著你如果直接按上面這樣定義的話,就會報錯的。會報什麼錯呢?會報如下的錯誤。
這意思就是不能重復定義A函數,報錯的行數也正是下面這行。
public function test($a){
所以說php是並不直接支持重載的。合著說了這麼半天php並不支持。。別急,我說的是並不直接支持,所以說是我們可以讓php間接支持。這時候就要用到一個函數來支持重載了。就是__call()。__call()方法必須帶有兩個參數。第一個包含了被調用的方法名稱,而第二個參數包含了傳遞給該方法的參數數組。可以通過這個方法實現類似於函數重載的功能。看下面的代碼。
public function __call($method,$p) { if($method=="display"){ if(is_object($p[0])){ $this->displayObject($p[0]); }else if(is_array($p[0])){ $this->displayArray($p[0]); }else{ $this->displayScalar($p[0]); } } }
//下面是對上面定義的調用 $ov=new overload; $ov->display(array(1,2,3)); $ov->display('cat');
定義方法的時候,可以看到有三個分支,如果一個對象傳遞給display()方法,就調用的是displayObject()方法;如果傳遞的是一個數組,調用displayArray();傳遞的是其他的內容的話,則調用的是displayScalar()方法。。。可以看到下面調用時,第一個是傳遞了一個數組,則調用displayArray()。第二個傳入的不是對象也不是數組,則屬於其他內容,調用的是displayScalar()方法。所以這樣子就用__call()方法實現了類似於其他語言的方法重載。
所謂覆蓋,從本質上來說就是重寫。就是當子類繼承父類的一些方法後,子類又在其內部定義了相同的方法,則這個新定義的方法會覆蓋繼承而來的父類的方法,子類只能調用其內部定義的方法。
有以下幾點要求:
1.當一個父類和子類有一個方法,參數和名字完全一致,那麼子類方法會覆蓋父類的方法。
2.在實行方法覆蓋的時候,訪問修飾符可以是不一樣的,但是子類的訪問范圍必須大於等於父類的訪問范圍。
3.要求參數和名字一樣。並不是要求子類,父類名稱相同。
下面是對這幾點的解釋:
第一點,必須參數一致,才會實現方法覆蓋。當參數個數不一致,則會報錯(這就牽扯到上面說所得方法重載)。當方法名字不一致,就不會覆蓋,只是子類新定義的方法。;
第二點,這是php這些語言設計時的規定吧。我是這麼理解的是訪問高一層的東西比較容易,如果再去訪問底層的東西權限肯定要高一些。
看代碼:
class people{ protected function sing(){ echo "人唱歌"; } } class woman extends people{ public function sing(){ echo "女人唱歌"; } } $woman1=new woman(); $woman1->sing();
這樣很正常的可以輸出“女人唱歌”。但當把woman裡的sing()方法改為proctcted,父元素改成public()時,即將父類的訪問權限設置的大於子類後,就會報下面的錯誤。
第三點,是要求參數和名字一樣,具體就是要求參數的個數與父類相同,而並不是參數名稱一致。即傳遞的參數名字可以為任意,只要保證傳遞的個數相同即可。
上面簡介了PHP語言中多態的兩個實現。
嗯,差不多就是這樣。。