什麼是多態?
多態(Polymorphism)按字面的意思就是「多種狀態」。在物件導向語言中,介面的多種不同的實作方式即為多態。引用Charlie Calverts對多態的描述-多態性是允許你將父物件設定為和一個或更多的他的子物件相等的技術,賦值之後,父物件就可以根據目前賦值給它的子對象的特性以不同的方式運作(摘自「Delphi4程式設計技術內幕」)。簡單的說,就是一句話:允許將子類別類型的指標賦值給父類別類型的指標(沒錯這段話來自百度百科)。那麼多態的作用是什麼,它有什麼實際開發價值呢?在實際的應用開發中,採用物件導向中的多態主要在於可以將不同的子類別物件當作一個父類別來處理,並且可以屏蔽不同子類別物件之間所存在的差異,寫出通用的程式碼,做出通用的編程,以適應需求的不斷變化。
以下是PHP中多態的兩個實作
方法重載( overload)
重載是類別的多型別的實作。函數重載指一個標識符被用作多個函數名,並且能夠透過函數的參數個數或參數型別將這些同名的函數區分開來,呼叫不發生混淆。即當呼叫的時候,雖然方法名字相同,但根據參數的不同可以自動呼叫對應的函數。
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()方法實作了類似其他語言的方法重載。
方法覆蓋(override)
#所謂覆寫,本質上就是重寫。就是當子類別繼承父類別的一些方法後,子類別在其內部定義了相同的方法,則這個新定義的方法會覆寫繼承而來的父類別的方法,子類別只能呼叫其內部定義的方法。
有以下幾點要求:
#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语言中多态的两个实现。
PS:重写、覆盖、重载、多态几个概念的区别分析
override->重写(=覆盖)、overload->重载、polymorphism -> 多态
override是重写(覆盖)了一个方法,以实现不同的功能。一般是用于子类在继承父类时,重写(重新实现)父类中的方法。
重写(覆盖)的规则:
1、重写方法的参数列表必须完全与被重写的方法的相同,否则不能称其为重写而是重载.
2、重写方法的访问修饰符一定要大于被重写方法的访问修饰符(public>protected>default>private)。
3、重写的方法的返回值必须和被重写的方法的返回一致;
4、重写的方法所抛出的异常必须和被重写方法的所抛出的异常一致,或者是其子类;
5、被重写的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行重写。
6、静态方法不能被重写为非静态的方法(会编译出错)。
overload是重载,一般是用于在一个类内实现若干重载的方法,这些方法的名称相同而参数形式不同。
重载的规则:
1、在使用重载时只能通过相同的方法名、不同的参数形式实现。不同的参数类型可以是不同的参数类型,不同的参数个数,不同的参数顺序(参数类型必须不一样);
2、不能通过访问权限、返回类型、抛出的异常进行重载;
3、方法的异常类型和数目不会对重载造成影响;
多态的概念比较复杂,有多种意义的多态,一个有趣但不严谨的说法是:继承是子类使用父类的方法,而多态则是父类使用子类的方法。
一般,我们使用多态是为了避免在父类里大量重载引起代码臃肿且难于维护。
举个例子:
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."); // 多态 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() { //重写,实现多态 return 3; } } class Rectangle extends Shape { public int getSides(int i) { //重载 return i; } }
注意Triangle类的方法是重写,而Rectangle类的方法是重载。对两者比较,可以发现多态对重载的优点:
如果用重载,则在父类里要对应每一个子类都重载一个取得边数的方法;
如果用多态,则父类只提供取得边数的接口,至于取得哪个形状的边数,怎样取得,在子类里各自实现(重写)。
以上是php如何理解方法重載與多型方法覆蓋的詳細內容。更多資訊請關注PHP中文網其他相關文章!