优点
可以这么说,反射完整的描述了一个类或者对象的原型,
它可以用作文档生成,所以,我们可以用它对文档中的类进行扫描,逐个生成扫描文档。
反射可以探知类的内部结构
也可以用作hook来实现插件功能,还有就是可以做动态代理
缺点
反射的消耗也是不小的,我们在有另外一种方案的时候,尽量不要选择反射。
很多时候,善用某个东西,会使得我们的代码,简洁又优雅,但是不能贪多,比如这个反射API,用的多了,会破坏我们类的封装性,使得本不应该暴露的方法暴露了出来,这是优点也是缺点
反射类 可得到的信息
ReflectionObject 对象信息
ReflectionFunction() 函数定义所在的文件以及起始位置
ReflectionClass() 常量、属性、方法、命名空间、类是否为final或abstract等
ReflectionMethod() 方法修饰类型、方法名、方法注释等
反射机制的应用
动态代理:也叫委托请求,在委托模式中,有两个对象参与处理同一个请求,接受请求的对象将请求委托给另一个对象来处理
插件系统:利用反射机制自动获取插件列表以及其他相关信息
/**
* 类A
* zeng
*/
class A
{
public function t1() {
echo '我是一个不带参数的方法<br>';
}
public function t2($str) {
echo "我是一个带参数的方法t2,参数是:" .$str,'<br>';
}
private function t3() {
}
static function t4() {
echo '我是一个静态方法';
}
}
$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
//执行方法
//静态方法调用 invoke(null,参数)
//普通方法调用 invoke(实例对象,参数)
//私有方法不能用invoke调用
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);
//判断这个类是否实现了某个接口
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
)
)
*/