本文主要和大家分享PHP反射机制详解,内容包括1.自动生成文档2.实现 MVC 架构3.实现单元测试4.配合 DI 容器解决依赖,希望能帮助到大家。

1.自动生成文档

根据反射的分析类,接口,函数和方法的内部结构,方法和函数的参数,以及类的属性和方法,可以自动生成文档。<?phpclass 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) , "
";echo "属性列表:
";

printf("%-15s%-10s%-40s
", 'Name', 'Access', 'Comment');$attr = $ref->getProperties();foreach ($attr as $row) {

printf("%-15s%-10s%-40s
", $row->getName(), getAccess($row), getComment($row));

}echo "常量列表:
";

printf("%-15s%-10s
", 'Name', 'Value');$const = $ref->getConstants();foreach ($const as $key => $val) {

printf("%-15s%-10s
", $key, $val);

}echo "
";echo "方法列表
";

printf("%-15s%-10s%-30s%-40s
", 'Name', 'Access', 'Params', 'Comment');$methods = $ref->getMethods();foreach ($methods as $row) {

printf("%-15s%-10s%-30s%-40s
", $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.实现单元测试

一般情况下我们会对函数和类进行测试,判断其是否能够按我们预期返回结果,我们可以用反射实现一个简单通用的类测试用例。<?phpclass 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 "
";

testEqual('Calc@minus', -1, [1, 2]);

这是类的测试方法,也可以利用反射实现函数的测试方法。<?phpfunction 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 解决依赖注入问题。<?phpclass 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反射机制详解相关推荐

  1. 反射 数据类型_Java基础:反射机制详解

    一.什么是反射: (1)Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法.本质是JVM得到class对象之后,再通过class对象进行反编译,从而获取t对 ...

  2. java反射机制详解篇一(基础)

    反射基础 首先来看一下最常规的创建对象的方式: ObjectClass clazz = new ObjectClass(); 当程序执行到new ObjectClass的时候,java虚拟机会加载Ob ...

  3. java 反射机制详解

    火星十一郎 海纳百川, 有容乃大,QQ:791909235,Tel:13137910179 posts - 774, comments - 556, trackbacks - 0, articles ...

  4. Go 反射机制详解及实例 【Go语言圣经笔记】

    反射 Go语言提供了一种机制,能够在运行时更新变量或检查它们的值.调用它们的方法和它们支持的内在操作,而不需要在编译时就知道这些变量的具体类型.这种机制被称为反射(这里反射的定义和其他语言大体相同). ...

  5. JAVA基础--JAVA中的反射机制详解

    JAVA反射机制     JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法:这种动态获取的信息以及动态调用对象的方法的功能 ...

  6. java反射机制详解_Java反射机制详解

    Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反 ...

  7. java反射模式_Java反射机制详解

    对于一般的开发者,很少需要直接使用Java反射机制来完成功能开发,但是反射是很多框架譬如 Spring, Mybatis 实现的核心,反射虽小,能量却很大. 本文主要介绍反射相关的概念以及API的使用 ...

  8. [转]Java反射机制详解

    目录 1反射机制是什么 2反射机制能做什么 3反射机制的相关API ·通过一个对象获得完整的包名和类名 ·实例化Class类对象 ·获取一个对象的父类与实现的接口 ·获取某个类中的全部构造函数 - 详 ...

  9. java反射机制详解_JAVA反射机制详解_JSP/Java编程_互联网开发技术网_传播最新的编程技术_php361.com...

    今天,下午在和朋友聊天的时候,聊起了反射这个话题. 我们就从下面这个段简单的代码开始吧. 这个代码输出什么,想必大部分的读者跟我一样,会很快地知道答案:0 1 2 3 4 5 6 7 8 9.事实也是 ...

最新文章

  1. LeetCode简单题之托普利茨矩阵
  2. 100.X86的寻址方式
  3. PHP问题 —— 丢失SESSION
  4. 2020年线上农产品消费趋势报告
  5. php中mysqli 处理查询结果集的几个方法
  6. mongodb 总结
  7. Vue前端和Java后端 联调使用AES 前后端加密解密
  8. latex常用的公式
  9. 再见,Navicat!这个 IDEA 的兄弟,真香!
  10. java map 对象作为key_Java 将自定义的对象作为HashMap的key
  11. 数据结构串的基本操作及KMP算法
  12. cam350 不能打开光绘文件_用CAM350导出GERBER文件的基本步骤
  13. duilib开发(十二):使用自定义控件
  14. .NET 7 预览版来啦,我升级体验了
  15. Matlab画图技巧: 不需要敲代码的傻瓜式操作流程
  16. 为什么excel中取消隐藏行后仍然有隐藏的行
  17. 计算机无法进行磁盘碎片整理,无法运行磁盘碎片整理
  18. linux echo 时间
  19. 【UOJ #198】【CTSC 2016】时空旅行
  20. 我英语不好,能学会编程吗?你觉得呢 ?

热门文章

  1. Python中的多线程
  2. 音视频技术开发周刊 | 196
  3. 远程办公第五天,你还在扩容吗?
  4. CDN调试—Debug Headers
  5. MapReduce+Docker:Archer简化Netflix媒体处理
  6. 机器学习实战教程(四):朴素贝叶斯基础篇之言论过滤器
  7. CentOS 下线,TencentOS Server 全新登陆带来最强支持
  8. 鹅厂程序员最喜欢用什么编程语言?Leader写代码么?
  9. 腾讯AI Lab刘霁谈机器学习,异步计算和去中心化是两大杀器
  10. 网易视频云分享:如何搭建视频转码集群