什么是PHP攔截器?
英文名稱 “interceptor”,作用是 攔截 發送未定義的方法和屬性的消息。
先看一段代碼,定義了一個School類,實例化一個對象$obj,獲取一個未定義的屬性teacher,會發生什么呢?
<?php class School { } $obj = new School; var_dump($obj->teacher);
如果使用php命令行執行,可以看出,php報了一個未定義屬性的Notice, $obj->teacher值是空值,所以打印出NULL
[root@localhost php]# php538 interceptor.php PHP Notice: Undefined property: School::$teacher in /usr/local/sina_mobile/apache/htdocs/php/interceptor.php on line 11 NULL
這里說明一下,php命令行執行和瀏覽器頁面執行不一定完全一樣,我們可以看下面截圖,web server是 apache執行同樣腳本時候,apache回告瀏覽器的是未帶php報出的Notice,返回給瀏覽器的是一個200 OK,這里面存在這php和web server的交互以及web server和瀏覽器的交互問題。
針對前面的代碼,我們想,如果訪問teacher的時候,teacher屬性不存在,我們可以攔截到對teacher的調用請求,並且做一些操作,那么這個就是php的攔截器,php攔截器提供了多種方法,這里__get方法就是訪問未定義的屬性時候被調用的。我們看下面代碼和結果
<?php class School { function __get($var) { echo $var; echo "\r\n"; return "hello"; } public $name = "Tom"; } $obj = new School; var_dump($obj->teacher); var_dump($obj->name);
執行以下結果如下,說明一下,__get方法必須擁有一個參數,該參數就是調用的未定義的屬性名稱,函數會將return 結果賦值給該調用的未知屬性。
[root@localhost php]# php538 interceptor.php teacher string(5) "hello" string(3) "Tom"
php提供了哪些攔截器方法
在有些文章中,把php攔截器一起稱未php魔術方法,這里我們把這些方法做個整理
序號 | 方法名 | 作用 | 實現版本 |
1 | __get($property) | 訪問未定義的屬性時候,調用該方法 | >= PHP 5.3.0 |
2 | __set($property, $value) | 給未定義屬性設置值的時候,調用該方法 | >= PHP 5.3.0 |
3 | __isset($property) | 對未定義屬性調用isset()時,調用該方法 | >= PHP 5.1.0 |
4 | __unset($property) | 對未定義屬性調用unset()時,調用該方法 | >= PHP 5.1.0 |
5 | __call($property, $args_array) | 調用未定義方法時,執行該方法 | >= PHP 5.3.0 |
6 | __autoload($classname) | 請求類時,先執行該方法 | >= PHP 5.3.0 |
7 | __construct($args) | 一個類中,只有一個構造函數,new 類的時候,構造函數優先被執行 | |
8 | __destruct() | 一個類中,只有一個析構函數,釋放類的時候,析構函數被執行 | |
9 | __clone() | 使用clone創建對象副本時候,該方法被調用 | >= PHP 5.3.0 |
10 | __tostring() | __toString() 方法用於一個類被當成字符串時應怎樣回應 | >= PHP 5.2.0 |
11 | __sleep() | serialize() 函數會檢查類中是否存在一個魔術方法 __sleep()。如果存在,該方法會先被調用,然后才執行序列化操作 | >= PHP 5.3.0 |
12 | __wakeup() | unserialize() 會檢查是否存在一個 __wakeup() 方法 | >= PHP 5.3.0 |
13 | __set_state | 調用 var_export() 導出類時,此靜態 方法會被調用。 | >= PHP 5.3.0 |
14 | __invoke | 當嘗試以調用函數的方式調用一個對象時,__invoke() 方法會被自動調用。 | >= PHP 5.3.0 |
15 | __callstatic() | 用靜態方式中調用一個不可訪問方法時,__callStatic() 會被調用 | |
16 | __debugInfo() | 使用var_dump()打印對象的時候,該方法被調用 | >= PHP 5.6.0 |
詳細情況見 http://php.net/manual/zh/language.oop5.magic.php介紹
結論
在這里,可以把上表中序號1-5的方法稱之為攔截器方法,后面稱之為魔術方法,魔術方法可以理解成是提供給php程序員對php標准函數的"重寫", 可以理解成zend虛擬機,在解析php腳本的時候,發現一些未定義的方法屬性,或者發現一些提供用戶重載的標准函數,如clone,serialize等時候,優先查看是否有需要自行的魔術方法。
參考文獻:
《深入PHP面向對象、模式與實踐》(第3版)/(美)Zandstra,M. 著,陳浩等譯. 北京:人民郵電出版社,2011.7 ISDN 978-7-115-25624-9