PHP面向?qū)ο缶幊讨钊肜斫夥椒ㄖ剌d與方法覆蓋(多態(tài))
什么是多態(tài)?
多態(tài)(Polymorphism)按字面的意思就是“多種狀態(tài)”。在面向?qū)ο笳Z言中,接口的多種不同的實現(xiàn)方式即為多態(tài)。引用Charlie Calverts對多態(tài)的描述——多態(tài)性是允許你將父對象設置成為和一個或更多的他的子對象相等的技術(shù),賦值之后,父對象就可以根據(jù)當前賦值給它的子對象的特性以不同的方式運作(摘自“Delphi4編程技術(shù)內(nèi)幕”)。簡單的說,就是一句話:允許將子類類型的指針賦值給父類類型的指針(沒錯這段話來自百度百科)。那么多態(tài)的作用是什么,它有什么實際開發(fā)價值呢?在實際的應用開發(fā)中,采用面向?qū)ο笾械亩鄳B(tài)主要在于可以將不同的子類對象都當作一個父類來處理,并且可以屏蔽不同子類對象之間所存在的差異,寫出通用的代碼,做出通用的編程,以適應需求的不斷變化。
下面就是PHP中多態(tài)的兩個實現(xiàn)
方法重載(overload)
重載是類的多態(tài)的一種實現(xiàn)。函數(shù)重載指一個標識符被用作多個函數(shù)名,且能夠通過函數(shù)的參數(shù)個數(shù)或參數(shù)類型將這些同名的函數(shù)區(qū)分開來,調(diào)用不發(fā)生混淆。即當調(diào)用的時候,雖然方法名字相同,但根據(jù)參數(shù)的不同可以自動調(diào)用相應的函數(shù)。
class A{ public function test(){ echo "test1"; } public function test($a){ echo "test2"; } } $a=new A(); $a->test(); $a->test($a);
假如php直接支持方法重載的話。那么上面的例子執(zhí)行后傳參和不傳參就會返回不同的值。然而php并不直接支持重載,這就意味著你如果直接按上面這樣定義的話,就會報錯的。會報什么錯呢?會報如下的錯誤。
這意思就是不能重復定義A函數(shù),報錯的行數(shù)也正是下面這行。
public function test($a){
所以說php是并不直接支持重載的。合著說了這么半天php并不支持。。別急,我說的是并不直接支持,所以說是我們可以讓php間接支持。這時候就要用到一個函數(shù)來支持重載了。就是__call()。__call()方法必須帶有兩個參數(shù)。第一個包含了被調(diào)用的方法名稱,而第二個參數(shù)包含了傳遞給該方法的參數(shù)數(shù)組??梢酝ㄟ^這個方法實現(xiàn)類似于函數(shù)重載的功能??聪旅娴拇a。
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]); } } } //下面是對上面定義的調(diào)用 $ov=new overload; $ov->display(array(1,2,3)); $ov->display('cat');
定義方法的時候,可以看到有三個分支,如果一個對象傳遞給display()方法,就調(diào)用的是displayObject()方法;如果傳遞的是一個數(shù)組,調(diào)用displayArray();傳遞的是其他的內(nèi)容的話,則調(diào)用的是displayScalar()方法。。。可以看到下面調(diào)用時,第一個是傳遞了一個數(shù)組,則調(diào)用displayArray()。第二個傳入的不是對象也不是數(shù)組,則屬于其他內(nèi)容,調(diào)用的是displayScalar()方法。所以這樣子就用__call()方法實現(xiàn)了類似于其他語言的方法重載。
方法覆蓋(override)
所謂覆蓋,從本質(zhì)上來說就是重寫。就是當子類繼承父類的一些方法后,子類又在其內(nèi)部定義了相同的方法,則這個新定義的方法會覆蓋繼承而來的父類的方法,子類只能調(diào)用其內(nèi)部定義的方法。
有以下幾點要求:
1.當一個父類和子類有一個方法,參數(shù)和名字完全一致,那么子類方法會覆蓋父類的方法。
2.在實行方法覆蓋的時候,訪問修飾符可以是不一樣的,但是子類的訪問范圍必須大于等于父類的訪問范圍。
3.要求參數(shù)和名字一樣。并不是要求子類,父類名稱相同。
下面是對這幾點的解釋:
第一點,必須參數(shù)一致,才會實現(xiàn)方法覆蓋。當參數(shù)個數(shù)不一致,則會報錯(這就牽扯到上面說所得方法重載)。當方法名字不一致,就不會覆蓋,只是子類新定義的方法。;
第二點,這是php這些語言設計時的規(guī)定吧。我是這么理解的是訪問高一層的東西比較容易,如果再去訪問底層的東西權(quán)限肯定要高一些。
看代碼:
class people{ protected function sing(){ echo "人唱歌"; } } class woman extends people{ public function sing(){ echo "女人唱歌"; } } $woman1=new woman(); $woman1->sing();
這樣很正常的可以輸出“女人唱歌”。但當把woman里的sing()方法改為proctcted,父元素改成public()時,即將父類的訪問權(quán)限設置的大于子類后,就會報下面的錯誤。
第三點,是要求參數(shù)和名字一樣,具體就是要求參數(shù)的個數(shù)與父類相同,而并不是參數(shù)名稱一致。即傳遞的參數(shù)名字可以為任意,只要保證傳遞的個數(shù)相同即可。
以上內(nèi)容簡單介紹了PHP語言中多態(tài)的兩個實現(xiàn)。
PS:重寫、覆蓋、重載、多態(tài)幾個概念的區(qū)別分析
override->重寫(=覆蓋)、overload->重載、polymorphism -> 多態(tài)
override是重寫(覆蓋)了一個方法,以實現(xiàn)不同的功能。一般是用于子類在繼承父類時,重寫(重新實現(xiàn))父類中的方法。
重寫(覆蓋)的規(guī)則:
1、重寫方法的參數(shù)列表必須完全與被重寫的方法的相同,否則不能稱其為重寫而是重載.
2、重寫方法的訪問修飾符一定要大于被重寫方法的訪問修飾符(public>protected>default>private)。
3、重寫的方法的返回值必須和被重寫的方法的返回一致;
4、重寫的方法所拋出的異常必須和被重寫方法的所拋出的異常一致,或者是其子類;
5、被重寫的方法不能為private,否則在其子類中只是新定義了一個方法,并沒有對其進行重寫。
6、靜態(tài)方法不能被重寫為非靜態(tài)的方法(會編譯出錯)。
overload是重載,一般是用于在一個類內(nèi)實現(xiàn)若干重載的方法,這些方法的名稱相同而參數(shù)形式不同。
重載的規(guī)則:
1、在使用重載時只能通過相同的方法名、不同的參數(shù)形式實現(xiàn)。不同的參數(shù)類型可以是不同的參數(shù)類型,不同的參數(shù)個數(shù),不同的參數(shù)順序(參數(shù)類型必須不一樣);
2、不能通過訪問權(quán)限、返回類型、拋出的異常進行重載;
3、方法的異常類型和數(shù)目不會對重載造成影響;
多態(tài)的概念比較復雜,有多種意義的多態(tài),一個有趣但不嚴謹?shù)恼f法是:繼承是子類使用父類的方法,而多態(tài)則是父類使用子類的方法。
一般,我們使用多態(tài)是為了避免在父類里大量重載引起代碼臃腫且難于維護。
舉個例子:
public class Shape { public static void main(String[] args){ Triangle tri = new Triangle(); System.out.println("Triangle is a type of shape? " + tri.isShape());// 繼承 Shape shape = new Triangle(); System.out.println("My shape has " + shape.getSides() + " sides."); // 多態(tài) Rectangle Rec = new Rectangle(); Shape shape2 = Rec; System.out.println("My shape has " + shape2.getSides(Rec) + " sides."); //重載 } public boolean isShape(){ return true; } public int getSides(){ return 0 ; } public int getSides(Triangle tri){ //重載 return 3 ; } public int getSides(Rectangle rec){ //重載 return 4 ; } } class Triangle extends Shape { public int getSides() { //重寫,實現(xiàn)多態(tài) return 3; } } class Rectangle extends Shape { public int getSides(int i) { //重載 return i; } }
注意Triangle類的方法是重寫,而Rectangle類的方法是重載。對兩者比較,可以發(fā)現(xiàn)多態(tài)對重載的優(yōu)點:
如果用重載,則在父類里要對應每一個子類都重載一個取得邊數(shù)的方法;
如果用多態(tài),則父類只提供取得邊數(shù)的接口,至于取得哪個形狀的邊數(shù),怎樣取得,在子類里各自實現(xiàn)(重寫)。
- 解決PHP Opcache 緩存刷新、代碼重載出現(xiàn)無法更新代碼的問題
- php 使用 __call實現(xiàn)重載功能示例
- PHP面向?qū)ο蟪绦蛟O計模擬一般面向?qū)ο笳Z言中的方法重載(overload)示例
- PHP面相對象中的重載與重寫
- PHP中子類重載父類的方法【parent::方法名】
- php函數(shù)重載的替代方法--偽重載詳解
- php繼承中方法重載(覆蓋)的應用場合
- PHP使用方法重載實現(xiàn)動態(tài)創(chuàng)建屬性的get和set方法
- PHP利用func_get_args和func_num_args函數(shù)實現(xiàn)函數(shù)重載實例
- php面向?qū)ο笕ヂ?(八)重載新的方法
- php面向?qū)ο蟮姆椒ㄖ剌d兩種版本比較
- PHP重載基礎知識回顧
相關(guān)文章
PHP內(nèi)核學習教程之php opcode內(nèi)核實現(xiàn)
opcode是計算機指令中的一部分,用于指定要執(zhí)行的操作, 指令的格式和規(guī)范由處理器的指令規(guī)范指定,通過本文給大家介紹PHP內(nèi)核學習教程之php opcode內(nèi)核實現(xiàn),感興趣的朋友一起學習吧2016-01-01