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 相关文章推荐
BBS(php & mysql)完整版(一)
Oct 09 PHP
PHP常用函数小技巧
Sep 11 PHP
PHP面向对象分析设计的61条军规小结
Jul 17 PHP
rrmdir php中递归删除目录及目录下的文件
May 15 PHP
php 网上商城促销设计实例代码
Feb 17 PHP
在wamp集成环境下升级php版本(实现方法)
Jul 01 PHP
php实现最简单的MVC框架实例教程
Sep 08 PHP
PHP图片自动裁切应付不同尺寸的显示
Oct 16 PHP
php实现的xml操作类
Jan 15 PHP
php实现在站点里面添加邮件发送的功能
Apr 28 PHP
php格式化时间戳
Dec 17 PHP
phpstudy的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
PHP使用数组实现队列
2012/02/05 PHP
PHP自动识别字符集并完成转码详解
2013/08/02 PHP
PHP中CURL的CURLOPT_POSTFIELDS参数使用细节
2014/03/17 PHP
php数组中包含中文的排序方法
2014/06/03 PHP
Yii2使用自带的UploadedFile实现的文件上传
2016/06/20 PHP
Jquery实现三层遍历删除功能代码
2013/04/23 Javascript
jQuery 快速结束当前正在执行的动画
2013/11/20 Javascript
js实现上传图片预览的方法
2015/02/09 Javascript
javascript的变量、传值、传址、参数之间关系
2015/07/26 Javascript
jquery获取css的color值返回RGB的方法
2015/12/18 Javascript
20分钟打造属于你的Bootstrap站点
2016/07/27 Javascript
浅谈js基本数据类型和typeof
2016/08/09 Javascript
深入浅出ES6之let和const命令
2016/08/25 Javascript
BootStrap3中模态对话框的使用
2017/01/06 Javascript
微信小程序 网络请求(post请求,get请求)
2017/01/17 Javascript
vue使用drag与drop实现拖拽的示例代码
2017/09/07 Javascript
为什么使用koa2搭建微信第三方公众平台的原因
2018/05/16 Javascript
Bootstrap标签页(Tab)插件切换echarts不显示问题的解决
2018/07/13 Javascript
angular 实现同步验证器跨字段验证的方法
2019/04/11 Javascript
浅谈webpack和webpack-cli模块源码分析
2020/01/19 Javascript
vue中父子组件传值,解决钩子函数mounted只运行一次的操作
2020/07/27 Javascript
Python中处理字符串之islower()方法的使用简介
2015/05/19 Python
Python Tkinter实现简易计算器功能
2018/01/30 Python
Python递归函数 二分查找算法实现解析
2019/08/12 Python
解决TensorFlow训练内存不断增长,进程被杀死问题
2020/02/05 Python
浅谈python锁与死锁问题
2020/08/14 Python
金智子午JAVA面试题
2015/09/04 面试题
既然说Ruby中一切都是对象,那么Ruby中类也是对象吗
2013/01/26 面试题
2014学习全国两会精神心得体会2000字
2014/03/11 职场文书
民主生活会对照检查材料(统计局)
2014/09/21 职场文书
2014最新毕业证代领委托书
2014/09/26 职场文书
实习科室评语
2015/01/04 职场文书
《分数乘法》教学反思
2016/02/24 职场文书
PHP判断是否是json字符串
2021/04/01 PHP
【海涛解说】史上最给力比赛,挑战DOTA极限
2022/04/01 DOTA
MySQL外键约束(Foreign Key)案例详解
2022/06/28 MySQL