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 相关文章推荐
解决了Ajax、MySQL 和 Zend Framework 的乱码问题
Mar 03 PHP
PHP中如何调用webservice的实例参考
Apr 25 PHP
input file获得文件根目录简单实现
Apr 26 PHP
php中的curl_multi系列函数使用例子
Jul 29 PHP
ThinkPHP入库出现两次反斜线转义及数据库类转义的解决方法
Nov 04 PHP
php恢复数组的key为数字序列的方法
Apr 28 PHP
Linux系统中设置多版本PHP共存配合Nginx服务器使用
Dec 21 PHP
PHP单态模式简单用法示例
Nov 16 PHP
PHP中串行化用法示例
Nov 16 PHP
使用WAMP搭建PHP本地开发环境
May 10 PHP
laravel框架语言包拓展实现方法分析
Nov 22 PHP
PHP设计模式之建造者模式(Builder)原理与用法案例详解
Dec 12 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 和 MYSQL
2006/10/09 PHP
php5.2.0内存管理改进
2007/01/22 PHP
php Undefined index和Undefined variable的解决方法
2008/03/27 PHP
PHP函数常用用法小结
2010/02/08 PHP
一个基于PDO的数据库操作类
2011/03/24 PHP
PHP分页详细讲解(有实例)
2013/10/30 PHP
ThinkPHP删除栏目(实现批量删除栏目)
2017/06/21 PHP
基于jquery的一个OutlookBar类,动态创建导航条
2010/11/19 Javascript
Js四则运算函数代码
2012/07/21 Javascript
jQuery创建平滑的页面滚动(顶部或底部)
2013/02/26 Javascript
目前流行的JavaScript库的介绍及对比
2013/09/29 Javascript
javascript内存管理详细解析
2013/11/11 Javascript
JQuery中serialize() 序列化
2015/03/13 Javascript
javaScript canvas实现(画笔大小 颜色 橡皮的实例)
2017/11/28 Javascript
jQuery NProgress.js加载进度插件的简单使用方法
2018/01/31 jQuery
JS实现根据指定值删除数组中的元素操作示例
2018/08/02 Javascript
js事件机制----捕获与冒泡机制实例分析
2020/05/22 Javascript
vue watch监控对象的简单方法示例
2021/01/07 Vue.js
python类:class创建、数据方法属性及访问控制详解
2016/07/25 Python
Python使用folium excel绘制point
2019/01/03 Python
python多个模块py文件的数据共享实例
2019/01/11 Python
Python pip替换为阿里源的方法步骤
2019/07/02 Python
PyCharm中Matplotlib绘图不能显示UI效果的问题解决
2020/03/12 Python
pycharm如何设置官方中文(如何汉化)
2020/12/29 Python
HTML5的postMessage的使用手册
2018/12/19 HTML / CSS
h5页面背景图很长要有滚动条滑动效果的实现
2021/01/27 HTML / CSS
Linux机考试题
2015/10/16 面试题
小学英语教学反思案例
2014/02/04 职场文书
洗车工岗位职责
2014/03/15 职场文书
《新型玻璃》教学反思
2014/04/13 职场文书
高一新生军训方案
2014/05/12 职场文书
2015年党员个人自我评价
2015/03/03 职场文书
windows下快速安装nginx并配置开机自启动的方法
2021/05/11 Servers
MySQL Router实现MySQL的读写分离的方法
2021/05/27 MySQL
FFmpeg视频处理入门教程(新手必看)
2022/01/22 杂记
斗罗大陆八大特殊魂兽,龙族始祖排榜首,第五最残忍(翠魔鸟)
2022/03/18 国漫