您的位置:首页 > 编程学习 > > 正文

php小例子(PHP反射实际应用示例)

更多 时间:2022-03-31 16:54:05 类别:编程学习 浏览量:2656

php小例子

PHP反射实际应用示例

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

1.自动生成文档

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

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • <?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%-40s<br/>", 'Name', 'Access', 'Comment');
  • $attr = $ref->getProperties();
  • foreach ($attr as $row) {
  •   printf("%-15s%-10s%-40s<br/>", $row->getName(), getAccess($row), getComment($row));
  • }
  • echo "常量列表:<br/>";
  • printf("%-15s%-10s<br/>", 'Name', 'Value');
  • $const = $ref->getConstants();
  • foreach ($const as $key => $val) {
  •   printf("%-15s%-10s<br/>", $key, $val);
  • }
  • echo "<br/><br/>";
  • echo "方法列表<br/>";
  • printf("%-15s%-10s%-30s%-40s<br/>", 'Name', 'Access', 'Params', 'Comment');
  • $methods = $ref->getMethods();
  • foreach ($methods as $row) {
  •   printf("%-15s%-10s%-30s%-40s<br/>", $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) 的名称,之后使用反射实现自动调用。

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • $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.实现单元测试

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

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • <?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]);
  • 这是类的测试方法,也可以利用反射实现函数的测试方法。

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • <?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 解决依赖注入问题。

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • <?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程序设计有所帮助。

    原文链接:https://blog.csdn.net/z15818264727/article/details/79375544

    标签:PHP 反射
    您可能感兴趣