PHP教學-多載(overload)魔術方法應用

物件導向中包含封裝、繼承、多型,其中以多型來講PHP也支援多載(重載)(overload)及覆寫(override),本篇是探討 PHP 多型中的重載( overload )。

PHP中的"多載"與其它絕大多數物件導向語言例如 JAVA、C++、C# 不同。傳統的""是用於提供多個同名的類方法,但各方法的參數類型和個數不同。如果 PHP 也在類別中定義多個同名但方法和參數類型都不同,那麼會發生錯誤。


*使用在屬性多載的魔術方法

1. __set($name, $value):如果想要寫入物件無法存取的屬性,就會觸發這個方法
2. __get($name):如果想要讀取物件無法存取的屬性,就會觸發這個方法
3. __isset($name):如果想要用isset()或是empty()判斷物件所無法存取的屬性是否存在或為空,就會觸發這個方法
4. __unset($name):如果想要用unset()來清除物件無法存取的屬性,就會觸發這個方法

用一個最簡單的例子來看:
檢視原始檔複製到剪貼簿列印關於

    <?php 
    class a { 
      function __get($name) { 
        if($name==='var1') return 'abc'; 
      } 
    } 
     
    $a = new a; 
    echo $a->var1."\n"; 
    echo $a->var2."\n"; 
     
    class b { 
      private $var1 = 'abc'; 
      private $var2 = 'def'; 
      function __get($name) { 
        switch($name) { 
          case 'var1':  
            return $this->var1; 
            break; 
          case 'var2': 
            return 'ghi'; 
            break; 
        } 
      } 
    } 
     
    $b = new b; 
    echo $b->var1."\n"; 
    echo $b->var2."\n"; 
     
    class c {} 
     
    $c = new c; 
    echo $c->var1."\n"; 



執行結果是:
檢視原始檔複製到剪貼簿列印關於

    Feng-Hsu-Pingteki-MacBook-Air:ironman6 fillano$ php 1-1a.php 
    abc 
     
    abc 
    ghi 
    PHP Notice:  Undefined property: c::$var1 in /Users/fillano/builds/ironman6/1-1a.php on line 34 



可以看出,只要是物件未定義或是無法存取的屬性,在讀取時就會會觸發這個方法。如果連這個方法都沒定義,就只好報錯。__set()、__isset()、__unset()都是類似的作用。

*使用在方法多載的魔術方法

1. __call($name, $args) :呼叫了物件未定義或無法存取的方法時觸發,$name是呼叫的方法名,$args是參數陣列
2. __callStatic($name, $args) (php5.3~) :呼叫了物件未定義或無法存取的靜態方法時觸發,$name是呼叫的方法名,$args是參數陣列

簡單的例子:
檢視原始檔複製到剪貼簿列印關於

    <?php 
    class a { 
      function __call($name, $args) { 
        echo $name . " : " . print_r($args, true) . "\n"; 
      } 
    } 
     
    $a = new a; 
    $a->func1('abc', 'def'); 
     
    class b { 
      function __call($name, $args) { 
        switch($name) { 
          case 'add': 
            if(count($args)===2) { 
              if(is_numeric($args[0]) && is_numeric($args[1])) 
                return $args[0]+$args[1]; 
              if(is_string($args[0]) && is_string($args[1])) 
                return $args[0].$args[1]; 
            } 
          default: 
            throw new Exception("[warning] b::$name method not found.\n"); 
        } 
      } 
    } 
     
    $b = new b; 
    echo $b->add(2,3)."\n"; 
    echo $b->add('hello', ' world.')."\n"; 
    try { 
      echo $b->add(2, ' world.')."\n";   
    } 
    catch (Exception $e) { 
      echo $e->getMessage(); 
    } 



執行結果:
檢視原始檔複製到剪貼簿列印關於

    Feng-Hsu-Pingteki-MacBook-Air:ironman6 fillano$ php 1-1b.php 
    func1 : Array 
    ( 
        [0] => abc 
        [1] => def 
    ) 
     
    5 
    hello world. 
    [warning] b::add method not found. 



這裡模擬了參數型別來判斷處理方式的多載,傳入兩個數字給add時,他會相加,傳入兩個字串時,會把字串接起來。但是傳給一個數字及一個字串,就會出現警告:找不到方法。

__callStatic跟__call類似,只是作用在使用::呼叫靜態方法時,這是從PHP5.3才有的魔術方法。

*用途???

PHP的多載,可以讓需要動態產生大量不同屬性或方法的物件時,處理更簡單。例如要開發ORM,使用物件對應到不同資料表的列時,我們實際上並不需要根據不同資料表的不同欄位來定義不同的類別,只要利用PHP的多載...然後在__get()、__call()等方法裡面檢查查詢的結果,並根據傳入的參數判斷要回傳的資料,操作起來感覺就好像不同的類別實例。(感謝大神的教導)

但是如果不是可以發揮這類集中處理的長處時,恐怕就需要評估一下了。因為這樣反而會讓一個方法太複雜,比較難維護與理解。

總之,PHP的多載跟別人不太一樣,但是用對地方的話就很對頭。

留言

這個網誌中的熱門文章

c語言-關於#define用法

CMD常用網管指令

PHP 與 JavaScript 之間傳值利用 json