反射,直觀理解就是根據到達地找到出發地和來源。好比,一個光禿禿的對象,咱們能夠僅僅經過這個對象就能知道它所屬的類、擁有哪些方法。php
反射是指在PHP運行狀態中,擴展分析PHP程序,導出或提出關於類、方法、屬性、參數等的詳細信息,包括註釋。這種動態獲取信息以及動態調用對象方法的功能稱爲反射API。mysql
ReflectionClass: 獲取類聲明時的結構sql
ReflectionObject: 可獲取類實例化後的結構數據庫
代碼以下:
class test{
private $name;
private $sex;
function __construct(){
$this->aaa='aaa';
}
}
$test=new test();
$reflect=new ReflectionClass($test);
$pro=$reflect->getDefaultProperties();
print_r($pro);//打印結果:Array ( [name] => [sex] => )
echo $test->aaa;//打印結果:aaa數組
在這個test類中,聲明瞭兩個成員變量$name和$sex,可是在構造函數中,又聲明瞭一個變量$aaa,初始化類,使用反射類打印默認成員屬性只有聲明的兩個成員變量屬性,可是打印類的$aaa變量發現仍是能夠輸出結果。
請問類的成員變量不用聲明,在函數中聲明也是能夠的嗎,有什麼區別?
在你這個例子中,使用ReflectionClass是不恰當的,由於__construct只有在實例化class時,纔會執行。
也就是說ReflectionClass更多的是反射類聲明時的結構,而不是類實例化後的結構,因此沒有輸出屬性aaa是正確,由於屬性aaa確實是(在類聲明時)不存在的。
那麼怎麼看屬性aaa呢,應該用ReflectionObject反射實例化後的結構,例如函數
代碼以下:
<?php
class test{
private $name;
private $sex;
function __construct(){
$this->aaa='aaa';
}
}
$test=new test();
$reflect=new ReflectionObject($test);
$pro=$reflect->getProperties();
print_r($pro);this
通過實例化之後,屬性aaa纔會存在,這時你就能看到屬性aaa了spa
例子:插件
1代理 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
如今,要獲取這個student對象的方法和屬性列表該怎麼作呢?如如下代碼所示:
1 2 3 4 5 6 7 8 9 10 11 |
|
也能夠不用反射API,使用class函數,返回對象屬性的關聯數組以及更多的信息:
1 2 3 4 5 6 |
|
假如這個對象是從其餘頁面傳過來的,怎麼知道它屬於哪一個類呢?一句代碼就能夠搞定:
1 2 |
|
反射API的功能顯然更強大,甚至能還原這個類的原型,包括方法的訪問權限等,如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
輸出以下:
1 2 3 4 5 6 7 8 |
|
不只如此,PHP手冊中關於反射API更是有幾十個,能夠說,反射完整地描述了一個類或者對象的原型。反射不只能夠用於類和對象,還能夠用於函數、擴展模塊、異常等。
反射能夠用於文檔生成。所以能夠用它對文件裏的類進行掃描,逐個生成描述文檔。
既然反射能夠探知類的內部結構,那麼是否是能夠用它作hook實現插件功能呢?或者是作動態代理呢?
例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
在日常開發中,用到反射的地方很少:一個是對對象進行調試,另外一個是獲取類的信息。在MVC和插件開發中,使用反射很常見,可是反射的消耗也很大,在能夠找到替代方案的狀況下,就不要濫用。
PHP有Token函數,能夠經過這個機制實現一些反射功能。從簡單靈活的角度講,使用已經提供的反射API是可取的。
不少時候,善用反射能保持代碼的優雅和簡潔,但反射也會破壞類的封裝性,由於反射可使本不該該暴露的方法或屬性被強制暴露了出來,這既是優勢也是缺點。