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 相关文章推荐
关于mysql 字段的那个点为是定界符
Jan 15 PHP
php出现Cannot modify header information问题的解决方法大全
Apr 09 PHP
PHP中uploaded_files函数使用方法详解
Mar 09 PHP
php中使用PHPExcel读写excel(xls)文件的方法
Sep 15 PHP
ThinkPHP模板中数组循环实例
Oct 30 PHP
php判断类是否存在函数class_exists用法分析
Nov 14 PHP
PHP实现Javascript中的escape及unescape函数代码分享
Feb 10 PHP
图文介绍PHP添加Redis模块及连接
Jul 28 PHP
PHP使用逆波兰式计算工资的方法
Jul 29 PHP
php中实现进程锁与多进程的方法
Sep 18 PHP
thinkphp3.2.3版本的数据库增删改查实现代码
Sep 22 PHP
php 比较获取两个数组相同和不同元素的例子(交集和差集)
Oct 18 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
水质对咖图啡风味的影响具体有哪些
2021/03/03 冲泡冲煮
PHP安装攻略:常见问题解答(三)
2006/10/09 PHP
phpmail类发送邮件函数代码
2012/02/20 PHP
WordPress迁移时一些常见问题的解决方法整理
2015/11/24 PHP
CodeIgniter框架验证码类库文件与用法示例
2017/03/18 PHP
PHP基于方差和标准差计算学生成绩的稳定性示例
2017/07/04 PHP
php-msf源码详解
2017/12/25 PHP
jQuery 页面载入进度条实现代码
2009/02/08 Javascript
JS中生成随机数的用法及相关函数
2016/01/09 Javascript
利用jquery获取select下拉框的值
2016/11/23 Javascript
EasyUI学习之Combobox级联下拉列表(2)
2016/12/29 Javascript
fullCalendar中文API官方文档
2017/02/07 Javascript
微信小程序 ES6Promise.all批量上传文件实现代码
2017/04/14 Javascript
jquery实现左右轮播切换效果
2018/01/01 jQuery
解决vue中对象属性改变视图不更新的问题
2018/02/23 Javascript
JS原型和原型链原理与用法实例详解
2020/02/05 Javascript
JavaScript文档加载模式以及元素获取
2020/07/28 Javascript
toString.call()通用的判断数据类型方法示例
2020/08/28 Javascript
查看Python安装路径以及安装包路径小技巧
2015/04/28 Python
python编程实现归并排序
2017/04/14 Python
python 动态加载的实现方法
2017/12/22 Python
Python对象属性自动更新操作示例
2018/06/15 Python
Django多层嵌套ManyToMany字段ORM操作详解
2020/05/19 Python
解决Python paramiko 模块远程执行ssh 命令 nohup 不生效的问题
2020/07/14 Python
SheIn俄罗斯:时尚女装网上商店
2017/02/28 全球购物
园林毕业生自我鉴定范文
2013/12/29 职场文书
财务管理专业求职信
2014/06/11 职场文书
安全生产目标管理责任书
2014/07/25 职场文书
办理护照工作证明
2014/10/10 职场文书
2014年旅游局法制宣传日活动总结
2014/11/01 职场文书
销售员岗位职责
2015/02/10 职场文书
电力工程合作意向书
2015/05/11 职场文书
收入证明范本
2015/06/12 职场文书
师范生见习总结范文
2015/06/23 职场文书
python使用openpyxl库读写Excel表格的方法(增删改查操作)
2021/05/02 Python
浅谈JS的二进制家族
2021/05/09 Javascript