優(yōu)點
可以這么說侣滩,反射完整的描述了一個類或者對象的原型,
它可以用作文檔生成口注,所以,我們可以用它對文檔中的類進行掃描君珠,逐個生成掃描文檔寝志。
反射可以探知類的內(nèi)部結(jié)構(gòu)
也可以用作hook來實現(xiàn)插件功能,還有就是可以做動態(tài)代理
缺點
反射的消耗也是不小的策添,我們在有另外一種方案的時候材部,盡量不要選擇反射。
很多時候唯竹,善用某個東西乐导,會使得我們的代碼,簡潔又優(yōu)雅浸颓,但是不能貪多物臂,比如這個反射API旺拉,用的多了,會破壞我們類的封裝性棵磷,使得本不應(yīng)該暴露的方法暴露了出來蛾狗,這是優(yōu)點也是缺點
反射類 可得到的信息
ReflectionObject 對象信息
ReflectionFunction() 函數(shù)定義所在的文件以及起始位置
ReflectionClass() 常量、屬性仪媒、方法沉桌、命名空間、類是否為final或abstract等
ReflectionMethod() 方法修飾類型规丽、方法名蒲牧、方法注釋等
反射機制的應(yīng)用
動態(tài)代理:也叫委托請求,在委托模式中赌莺,有兩個對象參與處理同一個請求冰抢,接受請求的對象將請求委托給另一個對象來處理
插件系統(tǒng):利用反射機制自動獲取插件列表以及其他相關(guān)信息
/**
* 類A
* zeng
*/
class A
{
public function t1() {
echo '我是一個不帶參數(shù)的方法<br>';
}
public function t2($str) {
echo "我是一個帶參數(shù)的方法t2,參數(shù)是:" .$str,'<br>';
}
private function t3() {
}
static function t4() {
echo '我是一個靜態(tài)方法';
}
}
$a = new A();
$ref_cls = new ReflectionClass('A');
$ref_method = $ref_cls->getMethod('t1');// 相當于new ReflectionMethod('A','t1')
//var_dump($ref_cls->hasMethod('t1'));//true
//var_dump($ref_method->isPublic());//true
//執(zhí)行方法
//靜態(tài)方法調(diào)用 invoke(null,參數(shù))
//普通方法調(diào)用 invoke(實例對象,參數(shù))
//私有方法不能用invoke調(diào)用
if( $ref_method->isPublic() && !$ref_method->isAbstract() )
{
if( $ref_method->isStatic() )
{
$ref_method->invoke(null);
}
else
{
$ref_method->invoke($a);//$a可以換成$ref_cls->newInstance();
}
}
/*
* isPublic
* isPrivate
* ....
* */
//$ref_cls_all_method = $ref_cls->getMethods();
//echo '<pre>';
//print_r($ref_cls_all_method);
/*
Array
(
[0] => ReflectionMethod Object
(
[name] => t1
[class] => A
)
[1] => ReflectionMethod Object
(
[name] => t2
[class] => A
)
[2] => ReflectionMethod Object
(
[name] => t3
[class] => A
)
[3] => ReflectionMethod Object
(
[name] => t4
[class] => A
)
)
*/
class A
{
function showInfo() {
echo 'Class A showinfo';
}
}
class B
{
private $obj;
function __construct() {
$this->obj = new A();
}
/*function addObj($obj) {
$this->obj[] = $obj;
}*/
function __call($name,$args) {
$ref_cls = new ReflectionClass($this->obj);
if($ref_cls->hasMethod($name))
{
$ref_method = $ref_cls->getMethod($name);
if( $ref_method->isPublic() && !$ref_method->isAbstract() )
{
if( $ref_method->isStatic() )
{
$ref_method->invoke(null);
}
else
{
$ref_method->invoke($this->obj);
}
}
}
}
}
$b = new B();
$b->showInfo();
Plugin.php
interface Plugin
{
function showMenu();
}
class MyPlugin implements Plugin
{
function showMenu() {
$menu = [
[
'name' => 'menu1',
'link' => 'index.php?id=1'
],
[
'name' => 'menu2',
'link' => 'index.php?id=2'
],
[
'name' => 'menu3',
'link' => 'index.php?id=3'
]
];
return $menu;
}
}
class HisPlugin implements Plugin
{
function showMenu() {
$menu = [
[
'name' => 'menu4',
'link' => 'index.php?id=4'
],
[
'name' => 'menu5',
'link' => 'index.php?id=5'
],
[
'name' => 'menu6',
'link' => 'index.php?id=6'
]
];
return $menu;
}
}
------------------------------------------
demo.php
include __DIR__ . '/Plugin.php';
function get_plugin_menus() {
$all_class = get_declared_classes();
$menus = $menu = [];
foreach ($all_class as $cls) {
$ref_cls = new ReflectionClass($cls);
//判斷這個類是否實現(xiàn)了某個接口
if($ref_cls->implementsInterface('Plugin')) {
//echo $cls; //MyPlugin HisPlugin
if($ref_cls->hasMethod('showMenu')){
$ref_method = $ref_cls->getMethod('showMenu');
if( $ref_method->isPublic() && !$ref_method->isAbstract() )
{
if( $ref_method->isStatic() )
{
$menu = $ref_method->invoke(null);
}
else
{
//$ref_method->invoke(new $cls());
//通過反射類獲取類的一個實例
$instance = $ref_cls->newInstance();
$menu = $ref_method->invoke($instance);
}
}
$menus = array_merge($menus,$menu);
}
}
}
return $menus;
}
$menu = get_plugin_menus();
echo '<pre>';
print_r($menu);
/*
Array
(
[0] => Array
(
[name] => menu1
[link] => index.php?id=1
)
[1] => Array
(
[name] => menu2
[link] => index.php?id=2
)
[2] => Array
(
[name] => menu3
[link] => index.php?id=3
)
[3] => Array
(
[name] => menu4
[link] => index.php?id=4
)
[4] => Array
(
[name] => menu5
[link] => index.php?id=5
)
[5] => Array
(
[name] => menu6
[link] => index.php?id=6
)
)
*/