php面试实现反射注入的详细方法


Posted in PHP onSeptember 30, 2019

PHP具有完整的反射API,提供了对类、接口、函数、方法和扩展进行逆向工程的能力。通过类的反射提供的能力我们能够知道类是如何被定义的,它有什么属性、什么方法、方法都有哪些参数,类文件的路径是什么等很重要的信息。正是因为类的反射,很多PHP框架才能实现依赖注入自动解决类与类之间的依赖关系,这给我们平时的开发带来了很大的方便。

本文主要是讲解如何利用类的反射来实现依赖注入(Dependency Injection),并不会去逐条讲述PHP Reflection里的每一个API。为了更好地理解,我们通过一个例子来看类的反射,以及如何实现依赖注入。

下面这个类代表了坐标系里的一个点,有两个属性横坐标x和纵坐标y。

/**

 * Class Point

 */

class Point

{

 public $x;

 public $y;

 

 /**

 * Point constructor.

 * @param int $x horizontal value of point's coordinate

 * @param int $y vertical value of point's coordinate

 */

 public function __construct($x = 0, $y = 0)

 {

 $this->x = $x;

 $this->y = $y;

 }

}

接下来这个类代表圆形,可以看到在它的构造函数里有一个参数是Point类的,即Circle类是依赖与Point类的。

class Circle

{

 /**

 * @var int

 */

 public $radius;//半径

 

 /**

 * @var Point

 */

 public $center;//圆心点

 

 const PI = 3.14;

 

 public function __construct(Point $point, $radius = 1)

 {

 $this->center = $point;

 $this->radius = $radius;

 }

 

 //打印圆点的坐标

 public function printCenter()

 {

 printf('center coordinate is (%d, %d)', $this->center->x, $this->center->y);

 }

 

 //计算圆形的面积

 public function area()

 {

 return 3.14 * pow($this->radius, 2);

 }

}

ReflectionClass

下面我们通过反射来对Circle这个类进行反向工程。把Circle类的名字传递给reflectionClass来实例化一个ReflectionClass类的对象。

$reflectionClass = new reflectionClass(Circle::class);

//返回值如下

object(ReflectionClass)#1 (1) {

 ["name"]=>

 string(6) "Circle"

}

反射出类的常量

$reflectionClass->getConstants();

返回一个由常量名称和值构成的关联数组

array(1) {

 ["PI"]=>

 float(3.14)

}

通过反射获取属性

$reflectionClass->getProperties();

返回一个由ReflectionProperty对象构成的数组

array(3) {

 [0]=>

 object(ReflectionMethod)#2 (2) {

 ["name"]=>

 string(11) "__construct"

 ["class"]=>

 string(6) "Circle"

 }

 [1]=>

 object(ReflectionMethod)#3 (2) {

 ["name"]=>

 string(11) "printCenter"

 ["class"]=>

 string(6) "Circle"

 }

 [2]=>

 object(ReflectionMethod)#4 (2) {

 ["name"]=>

 string(4) "area"

 ["class"]=>

 string(6) "Circle"

 }

}

我们还可以通过getConstructor()来单独获取类的构造方法,其返回值为一个ReflectionMethod对象。

$constructor = $reflectionClass->getConstructor();

反射出方法的参数

$parameters = $constructor->getParameters();

其返回值为ReflectionParameter对象构成的数组。

array(2) {

 [0]=>

 object(ReflectionParameter)#3 (1) {

 ["name"]=>

 string(5) "point"

 }

 [1]=>

 object(ReflectionParameter)#4 (1) {

 ["name"]=>

 string(6) "radius"

 }

}

依赖注入

好了接下来我们编写一个名为make的函数,传递类名称给make函数返回类的对象,在make里它会帮我们注入类的依赖,即在本例中帮我们注入Point对象给Circle类的构造方法。

//构建类的对象

function make($className)

{

 $reflectionClass = new ReflectionClass($className);

 $constructor = $reflectionClass->getConstructor();

 $parameters = $constructor->getParameters();

 $dependencies = getDependencies($parameters);

  

 return $reflectionClass->newInstanceArgs($dependencies);

}

 

//依赖解析

function getDependencies($parameters)

{

 $dependencies = [];

 foreach($parameters as $parameter) {

  $dependency = $parameter->getClass();

  if (is_null($dependency)) {

   if($parameter->isDefaultValueAvailable()) {

    $dependencies[] = $parameter->getDefaultValue();

   } else {

    //不是可选参数的为了简单直接赋值为字符串0

    //针对构造方法的必须参数这个情况

    //laravel是通过service provider注册closure到IocContainer,

    //在closure里可以通过return new Class($param1, $param2)来返回类的实例

    //然后在make时回调这个closure即可解析出对象

    //具体细节我会在另一篇文章里面描述

    $dependencies[] = '0';

   }

  } else {

   //递归解析出依赖类的对象

   $dependencies[] = make($parameter->getClass()->name);

  }

 }

 

 return $dependencies;

}

定义好make方法后我们通过它来帮我们实例化Circle类的对象:

$circle = make('Circle');

$area = $circle->area();

/*var_dump($circle, $area);

object(Circle)#6 (2) {

 ["radius"]=>

 int(1)

 ["center"]=>

 object(Point)#11 (2) {

 ["x"]=>

 int(0)

 ["y"]=>

 int(0)

 }

}

float(3.14)*/

通过上面这个实例我简单描述了一下如何利用PHP类的反射来实现依赖注入,Laravel的依赖注入也是通过这个思路来实现的,只不过设计的更精密大量地利用了闭包回调来应对各种复杂的依赖注入。

以上就是php面试怎么实现反射注入的详细内容,更多请关注三水点靠木其它相关文章!

PHP 相关文章推荐
提升PHP执行速度全攻略
Oct 09 PHP
PHP模拟SQL Server的两个日期处理函数
Oct 09 PHP
PHP获取163、gmail、126等邮箱联系人地址【已测试2009.10.10】
Oct 11 PHP
ajax在joomla中的原生态应用代码
Jul 19 PHP
ThinkPHP3.1新特性之多数据库操作更加完善
Jun 19 PHP
Laravel 5框架学习之向视图传送数据
Apr 08 PHP
必须收藏的23个php实用代码片段
Feb 02 PHP
在CentOS系统上从零开始搭建WordPress博客的全流程记录
Apr 21 PHP
PHP 中使用ajax时一些常见错误总结整理
Feb 27 PHP
在 Laravel 中 “规范” 的开发短信验证码发送功能
Oct 26 PHP
PHP 并发场景的几种解决方案
Jun 14 PHP
laravel框架添加数据,显示数据,返回成功值的方法
Oct 11 PHP
laravel5表单唯一验证的实例代码
Sep 30 #PHP
Laravel模糊查询区分大小写的实例
Sep 29 #PHP
基于laravel Request的所有方法详解
Sep 29 #PHP
基于Laravel 5.2 regex验证的正确写法
Sep 29 #PHP
php实现对文件压缩简单的方法
Sep 29 #PHP
Laravel 添加多语言提示信息的方法
Sep 29 #PHP
php实现登录页面的简单实例
Sep 29 #PHP
You might like
php使用curl详细解析及问题汇总
2016/08/11 PHP
10个值得深思的PHP面试题
2016/11/14 PHP
Aster vs KG BO3 第二场2.18
2021/03/10 DOTA
最新优化收藏到网摘代码(digg,diigo)
2007/02/07 Javascript
jQuery 类twitter的文本字数限制带提示效果插件
2010/04/16 Javascript
JS 对输入框进行限制(常用的都有)
2013/07/30 Javascript
JavaScript中“过于”犀利地for/in循环使用示例
2013/10/22 Javascript
Java/JS获取flash高宽的具体方法
2013/12/27 Javascript
JavaScript判断浏览器类型的方法
2015/02/10 Javascript
jquery实现的代替传统checkbox样式插件
2015/06/19 Javascript
JavaScript中的对象与JSON
2015/07/03 Javascript
原生js实现下拉框功能(支持键盘事件)
2017/01/13 Javascript
从零学习node.js之搭建http服务器(二)
2017/02/21 Javascript
jQuery实现select下拉框获取当前选中文本、值、索引
2017/05/08 jQuery
js实现首屏延迟加载实现方法 js实现多屏单张图片延迟加载效果
2017/07/17 Javascript
Nodejs中使用phantom将html转为pdf或图片格式的方法
2017/09/18 NodeJs
node.js中路由,中间件,ge请求和post请求的参数详解
2017/12/26 Javascript
vue-devtools的安装步骤
2018/04/23 Javascript
在vue2.0中引用element-ui组件库的方法
2018/06/21 Javascript
Vue实现左右菜单联动实现代码
2018/08/12 Javascript
一张图带我们入门Python基础教程
2017/02/05 Python
python使用opencv驱动摄像头的方法
2018/08/03 Python
Python打包方法Pyinstaller的使用
2018/10/09 Python
如何使用python把ppt转换成pdf
2019/06/29 Python
Python Pandas数据中对时间的操作
2019/07/30 Python
Python使用Pandas库常见操作详解
2020/01/16 Python
利用Python实现Json序列化库的方法步骤
2020/09/09 Python
C/C++ 笔试、面试题目大汇总
2015/11/21 面试题
出国留学自荐信
2013/10/25 职场文书
双语教学实施方案
2014/03/23 职场文书
挂靠协议书范本
2014/04/22 职场文书
儿童生日会策划方案
2014/05/15 职场文书
保送生自荐信
2015/03/06 职场文书
Python开发工具Pycharm的安装以及使用步骤总结
2021/06/24 Python
python中使用 unittest.TestCase单元测试的用例详解
2021/08/30 Python
Python实现科学占卜 让视频自动打码
2022/04/09 Python