一、前言
特別注意,雖然__call()或__callStatic()方法就是為實現重載而設計的,但是為了便於理解,先將兩者分開進行理解!!!
__call()方法的特性是它的特性,用其實現重載是實現重載,這是兩碼事~
二、__call()方法
在PHP5.3.0之后,又增加了一個__callStatic()方法。它們都是PHP中的魔術方法,所謂魔術方法,就是系統在特定時刻自動調用的方法!除了它們倆,PHP中還有其它一些魔術方法(見手冊)。對於魔術方法,個人理解是,各魔術方法有一個共同點:系統自動調用,有兩個不同點:調用的時間、調用之后產生的作用
對於__call()和__callStatic()的調用時間和功能(通俗點就是調用之后產生的結果),舉個栗子(代碼如下)
1 <?php 2 class A { 3 public function test () { 4 static::who(); 5 A::who(); 6 self::who(); 7 $this->who(); 8 } 9 10 /** 11 *私有方法 12 */ 13 private function test2(){ 14 15 } 16 17 public static function __callStatic($a, $b) { 18 var_dump('A static'); 19 } 20 21 public function __call($a, $b) { 22 var_dump('A call'); 23 } 24 } 25 26 $a = new A; 27 $a->test(); 28 A::test1(); 29 $a->test2(); 30 ?>
輸出為
通過這個栗子,不難看出兩點
·在類內部調用本類當中的一個不可訪問(如果是本類中,那就只能是不存在才不可訪問,如果是在本類外不可訪問還可能是沒有訪問權限)的方法時,不管是對象方式,還是靜態方式,都只能觸發__call()方法
·在類外部調用一個類中的一個不可訪問的方法時,對象方式就觸發__call()方法,靜態方式就觸發__callStatic()方法
ps,不可訪問不僅僅代表不存在
1、再舉個栗子
class MethodTest { public function __call($name,$arguments) { // 注意: $name 的值區分大小寫 echo "Calling object method '$name'的參數有多個,分別是:".implode ('、',$arguments)."<br/>" ; } /** PHP 5.3.0之后版本 */ public static function __callStatic($name,$arguments) { // 注意: $name 的值區分大小寫 echo "Calling static method'$name'的參數有多個,分別是:".implode ('、',$arguments)."<br/>" ; } } $obj=new MethodTest ; $obj->runTest ('in object context','另外一個參數'); MethodTest::runTest ('in static context','另外一個參數'); // PHP 5.3.0之后版本
輸出為
通過這個栗子,也不難看出兩點
·觸發__call()或__callStatic()方法時,系統會自動將所調用的那個不可訪問的方法的方法名作為第一個參數傳入__call()或__callStatic()方法中,而將所調用的不存在的方法傳入的參數,作為第二個參數(而且是封裝成了一個數組,即每一個元素就是調用不可訪問方法時傳入的一個參數)傳入__call()或__callStatic()方法中
·那么在__call或__callStatic()方法內部,就可以根據所傳入的兩個參數做一些操作,這就可以與重載掛上勾了!
2、額。。。最后舉個栗子
class Foo{ public function __call($name,$arguments){ print("你是想調用$name"."()方法嗎? 額...不好意思呦,該方法不可訪問!<br/>"); } } $foo=new Foo; $foo->doStuff(); $foo->doStuff1();
輸出為
二、重載
<?php /** *------------------------------------------------------------- *正是鑒於__call()或__callStatic()方法的這種特性,即所傳入的$name和$arguments,它們就用來實現重載!這點與JS每一個普通方法中都可以獲取到一個arguments數組其實異曲同工 *舉個例子 */ class Foo1{ public function __call($name,$arguments){ if($name=="doStuff"){ /** *實際上,不僅僅可以第一個參數類型,還可以判斷參數個數,以及參數順序,那么就和C++等強數據類型語言的重載效果是一樣的了! */ if(is_int($arguments[0])){ $this->doStuffForInt($arguments[0]); }else if(is_string($arguments[0])){ $this->doStuffForString($arguments[0]); } } } private function doStuffForInt($a){ echo "執行的是doStuffForInt()方法"; } private function doStuffForString($a){ echo "執行的是doStuffForString()方法"; } } $foo1=new Foo1; $foo1->doStuff('1');