Reflection反射机制

php5添加了一项新的功能:Reflection。这个功能使得程序员可以reflection class,interface,function,method …..。通过PHP代码,就可以得到某类/方法等的所有信息,并且可以和它交互。

反射类可得到的信息
ReflectionFunction()函数定义所在的文件以及起始位置等。
ReflectionClass()常量/属性/方法/命名空间/类是否为flnal或者abstract等。
ReflectionMethod()方法修饰类型/方法名/方法注释等。

使用方法

ReflectionFunction

<?php
/**
 * 测试函数
 * @author 启东
 */
function test(){
    echo "我是一个测试函数<br/>";
}
test();
$ref_fun = new ReflectionFunction('test');//反射函数类
echo $ref_fun->getDocComment(),"<br/>";//函数注释 如果new的是类 使用时类注释
//如果是方法  就是获取方法注释
echo "定义的所在文件名:",$ref_fun->getFileName(),"<br/>";//函数定义文件
echo "代码开始行".$ref_fun->getStartLine()."<br/>";//开始行
echo "代码结束行".$ref_fun->getEndLine()."<br/>";//结束行
 try {
     new ReflectionFunction("test1");
 }catch(ReflectionException $e){
    echo $e->getMessage(),"<br/>";
 };

ReflectionClass

<?php

class A{
    function t1(){
        echo "我是一个不带参数的方法<br/>";
    }
    function t2($str){
        echo "我是一个带一个参数的方法t2,参数是:",$str,"<br/>";
    }
    private function t3(){

    }
    static function t4(){
        echo "我是一个静态方法<br/>";
    }
}
$a=new A();
$ref_cls= new ReflectionClass('A');//参数可以是类名,也可以是类的一个实例
//获取类中的所有方法
$class_all_method=$ref_cls->getMethods();//获取这个类的所有方法
var_dump($class_all_method);
/**
F:\Work\test\test.php:21:
array (size=4)
0 =>
object(ReflectionMethod)[3]
public 'name' => string 't1' (length=2)
public 'class' => string 'A' (length=1)
1 =>
object(ReflectionMethod)[4]
public 'name' => string 't2' (length=2)
public 'class' => string 'A' (length=1)
2 =>
object(ReflectionMethod)[5]
public 'name' => string 't3' (length=2)
public 'class' => string 'A' (length=1)
3 =>
object(ReflectionMethod)[6]
public 'name' => string 't4' (length=2)
public 'class' => string 'A' (length=1)
 */
//判断类中是否有某个方法  hasMethod  返回布尔值
var_dump($ref_cls->hasMethod('t1')); //true
var_dump($ref_cls->hasMethod('tt'));//false

//判断方法的修饰符 public protected private static
//判断方式:is+修饰符 返回布尔值。
//判断之前获取类中的方法
$ref_method=$ref_cls->getMethod('t1');
var_dump($ref_method->isPublic());//判断是否是公开方法

ReflectionMethod

<?php
class A{
    function t1(){
        echo "我是一个不带参数的方法<br/>";
    }
    function t2($str){
        echo "我是一个带一个参数的方法t2,参数是:",$str,"<br/>";
    }
    private function t3(){
    }
    static function t4(){
        echo "我是一个静态方法<br/>";
    }
}
$a=new A();
$ref_cls= new ReflectionClass('A');//参数可以是类名,也可以是类的一个实例
//获取类中的方法的反射类
$ref_method=new ReflectionMethod($a,'t3');
var_dump($ref_method->isPublic());//是否公开方法

$ref_method=new ReflectionMethod('A','t4');
var_dump($ref_method->isStatic());//是否静态方法
//获取方法 然后执行方法
$ref_method=$ref_cls->getMethod('t1');
//静态方法调用  invoke(null,参数)
//普通方法调用  invoke(实例对象,参数)
//私有或受保护的方法不能被invoke调用
if($ref_method->isPublic() && !$ref_method->isAbstract()){
    if($ref_method->isStatic()){
        $ref_method->invoke(null);
    }else{
        $ref_method->invoke($a);
    }
}
//静态方法invoke调用
$ref_method=$ref_cls->getMethod('t4');
if($ref_method->isPublic() && !$ref_method->isAbstract()){
    if($ref_method->isStatic()){
        $ref_method->invoke(null);
    }else{
        $ref_method->invoke($a);
    }
}
//带参数的invoke调用
$ref_method=$ref_cls->getMethod('t2');
if($ref_method->isPublic() && !$ref_method->isAbstract()){
    if($ref_method->isStatic()){
        $ref_method->invoke(null);
    }else{
        $ref_method->invoke($a,'什么');
    }
}

动态代理

动态代理:也叫委托模式,在委托模式中,有两个对象参与处理同意个请求,接受请求的对象将请求委托给另一个对象来处理。

代码示例:

<?php
class A{
    function showInfo(){
        echo "Class A showInfo<br/>";
    }
}
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();

<?php
class A{

function showInfo(){
    echo "Class A showInfo<br/>";
}

}
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();

插件系统:利用反射机制自动获取插件列表以及其他的相关信息。

定义test.php文件代码示例如下

<?php
interface Plugin{
    function showMenu();
}
class MyPlugin implements Plugin{
    //获取插件菜单
    function showMenu()
    {
        $menu=array(
            array(
                'name'=>'menu1',
                'link'=>'index.php?act=link1'
            ),
            array(
                'name'=>'menu2',
                'link'=>'index.php?act=link2'
            )
        );
        return $menu;
    }
}

class YourPlugin implements Plugin{
    //获取插件菜单
    function showMenu()
    {
        $menu=array(
            array(
                'name'=>'menu3',
                'link'=>'index.php?act=your_link3'
            ),
            array(
                'name'=>'menu4',
                'link'=>'index.php?act=your_link4'
            )
        );
        return $menu;
    }
}

定义代码示例a.php 并运行a.php

<?php

include_once __DIR__.'/test.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')){
            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 {
                        //通过反射类获取类的一个实例
                        $instance=$ref_cls->newInstance();
                        $menu=$ref_method->invoke($instance);
                       //$ref_method->invoke(new $cls);
                    }
                }
            }
        }
        $menus=array_merge($menus,$menu);
    }
    return $menus;
}
$menu_list=get_plugin_menus();
var_dump($menu_list);
Last modification:January 7, 2020
如果觉得我的文章对你有用,请随意赞赏