• 企业400电话
  • 微网小程序
  • AI电话机器人
  • 电商代运营
  • 全 部 栏 目

    企业400电话 网络优化推广 AI电话机器人 呼叫中心 网站建设 商标✡知产 微网小程序 电商运营 彩铃•短信 增值拓展业务
    PHP反射实际应用示例

    本文实例讲述了PHP反射实际应用。分享给大家供大家参考,具体如下:

    1.自动生成文档

    根据反射的分析类,接口,函数和方法的内部结构,方法和函数的参数,以及类的属性和方法,可以自动生成文档。

    ?php
    class Student
    {
      const NORMAL = 1;
      const FORBIDDEN = 2;
      /**
       * 用户ID
       * @var 类型
       */
      public $id;
      /**
       * 获取id
       * @return int
       */
      public function getId()
      {
        return $this->id;
      }
      public function setId($id = 1)
      {
        $this->id = $id;
      }
    }
    $ref = new ReflectionClass('Student');
    $doc = $ref->getDocComment();
    echo $ref->getName() . ':' . getComment($ref) , "br/>";
    echo "属性列表:br/>";
    printf("%-15s%-10s%-40sbr/>", 'Name', 'Access', 'Comment');
    $attr = $ref->getProperties();
    foreach ($attr as $row) {
      printf("%-15s%-10s%-40sbr/>", $row->getName(), getAccess($row), getComment($row));
    }
    echo "常量列表:br/>";
    printf("%-15s%-10sbr/>", 'Name', 'Value');
    $const = $ref->getConstants();
    foreach ($const as $key => $val) {
      printf("%-15s%-10sbr/>", $key, $val);
    }
    echo "br/>br/>";
    echo "方法列表br/>";
    printf("%-15s%-10s%-30s%-40sbr/>", 'Name', 'Access', 'Params', 'Comment');
    $methods = $ref->getMethods();
    foreach ($methods as $row) {
      printf("%-15s%-10s%-30s%-40sbr/>", $row->getName(), getAccess($row), getParams($row), getComment($row));
    }
    // 获取权限
    function getAccess($method)
    {
      if ($method->isPublic()) {
        return 'Public';
      }
      if ($method->isProtected()) {
        return 'Protected';
      }
      if ($method->isPrivate()) {
        return 'Private';
      }
    }
    // 获取方法参数信息
    function getParams($method)
    {
      $str = '';
      $parameters = $method->getParameters();
      foreach ($parameters as $row) {
        $str .= $row->getName() . ',';
        if ($row->isDefaultValueAvailable()) {
          $str .= "Default: {$row->getDefaultValue()}";
        }
      }
      return $str ? $str : '';
    }
    // 获取注释
    function getComment($var)
    {
      $comment = $var->getDocComment();
      // 简单的获取了第一行的信息,这里可以自行扩展
      preg_match('/\* (.*) *?/', $comment, $res);
      return isset($res[1]) ? $res[1] : '';
    }
    
    

    输出结果:

    Student:
    属性列表:
    Name Access Comment
    id Public 用户ID
    常量列表:
    Name Value
    NORMAL 1
    FORBIDDEN 2
    方法列表
    Name Access Params Comment
    getId Public 获取id
    setId Public id,Default: 1

    2.实现 MVC 架构

    现在好多框架都是 MVC 的架构,根据路由信息定位控制器($controller) 和方法($method) 的名称,之后使用反射实现自动调用。

    $class = new ReflectionClass(ucfirst($controller) . 'Controller');
    $controller = $class->newInstance();
    if ($class->hasMethod($method)) {
      $method = $class->getMethod($method);
      $method->invokeArgs($controller, $arguments);
    } else {
      throw new Exception("{$controller} controller method {$method} not exists!");
    }
    
    

    3.实现单元测试

    一般情况下我们会对函数和类进行测试,判断其是否能够按我们预期返回结果,我们可以用反射实现一个简单通用的类测试用例。

    ?php
    class Calc
    {
      public function plus($a, $b)
      {
        return $a + $b;
      }
      public function minus($a, $b)
      {
        return $a - $b;
      }
    }
    function testEqual($method, $assert, $data)
    {
      $arr = explode('@', $method);
      $class = $arr[0];
      $method = $arr[1];
      $ref = new ReflectionClass($class);
      if ($ref->hasMethod($method)) {
        $method = $ref->getMethod($method);
        $res = $method->invokeArgs(new $class, $data);
        if($res === $assert){
          echo "测试结果正确";
        };
      }
    }
    testEqual('Calc@plus', 3, [1, 2]);
    echo "br/>";
    testEqual('Calc@minus', -1, [1, 2]);
    
    

    这是类的测试方法,也可以利用反射实现函数的测试方法。

    ?php
    function title($title, $name)
    {
      return sprintf("%s. %s\r\n", $title, $name);
    }
    $function = new ReflectionFunction('title');
    echo $function->invokeArgs(array('Dr', 'Phil'));
    ?>
    
    

    这里只是我简单写的一个测试用例,PHPUnit 单元测试框架很大程度上依赖了 Reflection 的特性,可以了解下。

    4.配合 DI 容器解决依赖

    Laravel 等许多框架都是使用 Reflection 解决依赖注入问题,具体可查看 Laravel 源码进行分析。

    下面我们代码简单实现一个 DI 容器演示 Reflection 解决依赖注入问题。

    ?php
    class DI
    {
      protected static $data = [];
      public function __set($k, $v)
      {
        self::$data[$k] = $v;
      }
      public function __get($k)
      {
        return $this->bulid(self::$data[$k]);
      }
      // 获取实例
      public function bulid($className)
      {
        // 如果是匿名函数,直接执行,并返回结果
        if ($className instanceof Closure) {
          return $className($this);
        }
        // 已经是实例化对象的话,直接返回
        if(is_object($className)) {
          return $className;
        }
        // 如果是类的话,使用反射加载
        $ref = new ReflectionClass($className);
        // 监测类是否可实例化
        if (!$ref->isInstantiable()) {
          throw new Exception('class' . $className . ' not find');
        }
        // 获取构造函数
        $construtor = $ref->getConstructor();
        // 无构造函数,直接实例化返回
        if (is_null($construtor)) {
          return new $className;
        }
        // 获取构造函数参数
        $params = $construtor->getParameters();
        // 解析构造函数
        $dependencies = $this->getDependecies($params);
        // 创建新实例
        return $ref->newInstanceArgs($dependencies);
      }
      // 分析参数,如果参数中出现依赖类,递归实例化
      public function getDependecies($params)
      {
        $data = [];
        foreach($params as $param)
        {
          $tmp = $param->getClass();
          if (is_null($tmp)) {
            $data[] = $this->setDefault($param);
          } else {
            $data[] = $this->bulid($tmp->name);
          }
        }
        return $data;
      }
      // 设置默认值
      public function setDefault($param)
      {
        if ($param->isDefaultValueAvailable()) {
          return $param->getDefaultValue();
        }
        throw new Exception('no default value!');
      }
    }
    class Demo
    {
      public function __construct(Calc $calc)
      {
        echo $calc->plus(1, 2);
      }
    }
    class Calc
    {
      public function plus($a, $b)
      {
        return $a + $b;
      }
      public function minus($a, $b)
      {
        return $a - $b;
      }
    }
    $di = new DI();
    $di->calc = 'Calc';
    $di->demo = 'Demo';
    $di->demo;//输出结果为3
    
    

    更多关于PHP相关内容感兴趣的读者可查看本站专题:《php面向对象程序设计入门教程》、《PHP数组(Array)操作技巧大全》、《PHP基本语法入门教程》、《PHP运算与运算符用法总结》、《php字符串(string)用法总结》、《php+mysql数据库操作入门教程》及《php常见数据库操作技巧汇总》

    希望本文所述对大家PHP程序设计有所帮助。

    您可能感兴趣的文章:
    • PHP的反射动态获取类方法、属性、参数操作示例
    • php面试实现反射注入的详细方法
    • PHP反射原理与用法深入分析
    • php提供实现反射的方法和实例代码
    • PHP进阶学习之反射基本概念与用法分析
    • php反射学习之不用new方法实例化类操作示例
    • PHP反射学习入门示例
    • 用PHP的反射实现委托模式的讲解
    • 浅析PHP类的反射来实现依赖注入过程
    • PHP基于反射机制实现自动依赖注入的方法详解
    • PHP基于反射获取一个类中所有的方法
    • PHP反射基础知识回顾
    上一篇:ThinkPHP3.2.3框架实现执行原生SQL语句的方法示例
    下一篇:ThinkPHP3.2.3框架实现的空模块、空控制器、空操作,跳转到错误404页面图文详解
  • 相关文章
  • 

    © 2016-2020 巨人网络通讯 版权所有

    《增值电信业务经营许可证》 苏ICP备15040257号-8

    PHP反射实际应用示例 PHP,反射,实际,应用,示例,