php的动态代理和反射

面向对象的高级语言都应该提供了反射机制,可以动态的获取类的信息,否则语言就缺少灵活性,很多需求无法完成,php的反射相当于iOS里面的运行时方法。iOS的运行系统提供了一系列的C语言方法动态的获取类的信息,处理消息转发,php也提供了类似的实现,相比iOS使用更简便,下面是几个案例。

  1. 获取函数的信息
<?php
/**
 * Created by PhpStorm.
 * User: wangguodong
 * Date: 17/3/2
 * Time: 下午10:44
 */

/**
 * 这是testfun的注释
 */
function testfun($name = 'test'){
    echo "this is a $name method";
    return 'a';
}

testfun();
//通过一个函数名初始化一个函数反射对象,取获取函数的相关信息
$ref_fun = new ReflectionFunction('testfun');
//函数的所在的文件
echo '<br>函数的文件位置是:'.$ref_fun->getFileName();
//获取函数的开始行编号
echo '<br>函数的起始位置是:'.$ref_fun->getStartLine();
//获取函数末尾的编号
echo '<br>函数的结束位置是:'.$ref_fun->getEndLine();
//函数的注释
echo '<br>函数的注释是:'.$ref_fun->getDocComment();
//获取参数的个数
echo '<br>函数的参数个数是:'.$ref_fun->getNumberOfParameters();
//获取具体的参数信息
echo '<br>函数的参数是:';print_r($ref_fun->getParameters());
//函数的返回值 --这里提示这个方法不存在
echo '<br>函数的返回值是:'.$ref_fun->getReturnType();

//如果反射一个不存在的函数,会抛出一个异常,应该try catch 使用
try{
    $ref_nfun = new ReflectionFunction('no_exist');
}catch (ReflectionException $e){
    echo $e->getMessage();
}

2.类的信息

class Person{

    public $name,$age,$sex;
    static function show($name,$age,$sex='男'){
        echo "姓名:$name,年龄:$age,性别:$sex";
    }
    function say($content){
        echo "我想说的是:$content";
    }
    function eat($food= 'apple'){

    }
}
$per = new Person();

$ref = new ReflectionClass('Person');//参数可以是类名,或者类的实例
//获取类里面的所有方法
$class_methods = $ref->getMethods();
//是一个数组,每个对象包含了方法名和所属类
echo '<br/>';
echo "<pre>";print_r($class_methods);echo "<pre>";
//是否拥有某个方法
$has_method = $ref->hasMethod('say');
//获取某个方法的信息
$some_method = new ReflectionMethod('Person','say');
$some_method->isPrivate();//判断是否私有,还有static,public
//方法的调用,
if ($some_method->isPublic()&&!$some_method->isAbstract()) {

    if ($some_method->isStatic()){
        //静态方法第一个参数是null,后面参数写方法的参数,可以传递一个或者多个,并且这个方法可以接受数量可变的参数。
        /*
         * * The object to invoke the method on. For static methods, pass
         * null to this parameter.
         * </p>
         * @param mixed $parameter [optional] <p>
         * Zero or more parameters to be passed to the method.
         * It accepts a variable number of parameters which are passed to the method.
         * </p>
         */
        $some_method->invoke(null,'zhangsan','23');
    }
    else {
        //非静态方法第一个参数传递一个对象
        $some_method->invoke($per,'生活真好');
    }
}
}
  1. 动态代理

消息的转发,交给其他类处理,iOS可以通过delegate实现,也可以在运行时通过相应的方法转发。

//调用B的show方法时候去调用A的show方法
class A{
    function show(){
        echo "classA的show方法";
    }
}
class B{
    private $obj;
    function __construct(){
        $this->obj = new A();
    }
    function __call($name, $arguments)
    {
         $ref = new ReflectionClass($this->obj);
         if ($ref->hasMethod($name)){
             $method = $ref->getMethod($name);
             if ($method->isPublic()&&!$method->isAbstract()&&count($arguments)){
                 if ($method->isStatic()){
                     $method->invoke(null);
                 }
                 else{
                     $method->invoke($this->obj);
                 }
             }
         }
    }
}
  1. 插件案例
include_once __DIR__."/plugin.php";
function get_plugin_menus(){
    $menus = array();
    $all_class = get_declared_classes();//获取所有的类
    foreach ($all_class as $cls){
        $ref_cls = new ReflectionClass($cls);
        if ($ref_cls->implementsInterface('Plugin')){//是否实现了某个接口
            if ($ref_cls->hasMethod('showMenu')){
                $method = $ref_cls->getMethod("showMenu");
                if ($method->isStatic()){
                    $method->invoke(null);
                }
                else{
//                    $method->invoke(new $cls());//这样获取类
                    $instance = $ref_cls->newInstance();
                    $menu = $method->invoke($instance);
                }
            }
        }
        $menus = array_merge($menus,$menu);
    }
    return $menus;
}
echo "<pre>";get_plugin_menus();echo "<pre>";

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;
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 175,888评论 25 709
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 14,321评论 4 61
  • 曾几何时,手机走进人们的生活,改变着传统的联系方式,原来当面可以说的事情现在可以通过手机和短信留言来完成,曾...
    伟嘉豪阅读 1,475评论 0 1
  • 这个中秋节,老王本打算静下来写写文章,但在无意间看到一部《麻雀》的谍战片,使得老王两眼冒金光,因为老王超喜欢...
    楚先生阅读 2,790评论 0 1
  • 致孤单的你 每个人都会有孤单寂寞的时候,并不是有人陪伴就不会孤单寂寞,孤单的时候学会独处,看一本书,听一首歌,写一...
    猴爸陪你读书阅读 2,629评论 0 1