php5之後實現了一些魔術方法還是比較有意思的,之前一直用面向過程的編程方法,對oop研究的比較少,最近在看oop的東西,還是比較有意思的。
魔術方法這些東西,感覺很大一部分就是為了偷懶用的,記得最早寫php的時候,那時候做部落格,用的是國外的一個叫lifetype的開源架構,那時候還是php4.3,但是那個架構裡全部實現了對象,所有的資料都被封裝到對象中。
於是當從db裡select出來一堆東西之後,還要逐個迴圈封裝成對象,每一個欄位也要實現getField()和getField()方法,寫起來還真有點麻煩,感覺就是在做重複性的工作。
那麼get(),set(),call(),callStatic()這幾個魔術方法的誕生,就完全解決了這個問題。
get()和set()是針對類中屬性的而call()是針對方法的,callStatic() 是針對靜態類的方法。
一、get()和set()魔術方法:
當執行個體化一個對象後,調用類中不存在或者沒有許可權訪問的屬性的時候,php會預設調用get()方法,這樣做,不僅可以少些很多代碼,讓結構更清晰,而且也提供了一條外部存取類的私人成員的一種方法。
比如:
<?phpclass testGet{ private $name = 'test';}$test = new testGet();$test->name;
上面的代碼,如果我們運行,會報一個錯誤:PHP Fatal error: Cannot access private property testGet::$name in /Library/WebServer/Documents/workspace/learn/call/a.php on line 7
但是我們修改一下,通過get()方法就可以訪問
<?phpclass testGet{ private $name = 'test'; function get($property) { if ( isset($this->$property) ) return $this->$property; else return NULL; }}$test = new testGet();echo $test->name . PHP_EOL;
代碼改成這樣之後我們再訪問就沒有問題。
注意:如果把屬性定義成是static的,那麼通過get()訪問也會報錯。原因是static的成員,是屬於類本身的,不因為執行個體化而改變,可以自己測試。
利用set()方法,可以禁止動態建立類屬性,這樣可以很好的避免給後來開發人員,或者程式維護者帶來不必要的麻煩。
funciton set($property) {
//$property接收的是屬性的名字
}
是實話,oop這個東西的設計,會摻雜很多設計者自己的思想,如果沒有文檔,後來者去讀代碼還是很費勁的,當然和後來者的水平也有很大關係。
下面是一個get和set配合使用的例子:
<?phpclass testGet{ private $name = 'test'; function get($property) { if ( isset($this->$property) ) return $this->$property; else return NULL; } public function set($property, $value) { if ( isset($this->$property) ) $this->$property = $value; else return NULL; }}$test = new testGet();$test->name = 'my test name';echo $test->name . PHP_EOL;
function set($property, $value) {
//$property接收的屬性的名字
//$value接收的是屬性的值
}
二、call()和callStatic()方法:
當對象調用類中一個不存在或者沒有許可權訪問的方法的時候,就會自動調用call()方法。
記得以前有個同事問我,tp架構中為什麼有很多底層的方法沒有,但是在上層還能調用,其實就是call()這個方法在起作用。
如果你不知道這個方法,那麼肯定會很疑惑,而且問題也不好定位。
<?phpabstract class Obj { private $objData = array(); /** * call魔術方法,如果對象請求的方法不存在或者沒有許可權訪問的時候 * 調用魔術方法 */ public function call($name, $args) { $field = preg_match('/^get(\w+)/', $name, $matches); if ( $field && $matches[1] ) return $this->objData[strtolower($matches[1])]; $field = preg_match('/^set(\w+)/', $name, $matches); if ( $field && $matches[1] ) { return $this->objData[strtolower($matches[1])] = $args[0]; } } }class User extends Obj{ }$user = new User();$user->setName('test');echo $user->getName();
User類什麼都沒幹,但是通過繼承類的call()方法,把所有的事都做了(getName和setName)。
function call($methodName, $args) {
//$methodName調用的方法名
//$args傳遞的參數數組
}
和call()對應的是callStatic()方法,是位靜態類的靜態方法服務的。
例子:
<?php abstract class Obj { private static $objData = array(); /** * call魔術方法,如果對象請求的方法不存在或者沒有許可權訪問的時候 * 調用魔術方法 */ public static function callStatic($name, $args) { $field = preg_match('/^get(\w+)/', $name, $matches); if ( $field && $matches[1] ) return self::$objData[strtolower($matches[1])]; $field = preg_match('/^set(\w+)/', $name, $matches); if ( $field && $matches[1] ) { return self::$objData[strtolower($matches[1])] = $args[0]; } } } class User extends Obj { } User::setName('test'); echo User::getName() . PHP_EOL;
三、延遲靜態繫結:static這個對象