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 相关文章推荐
Discuz 5.0 中读取纯真IP数据库函数分析
Mar 16 PHP
PHP 一个随机字符串生成代码
May 26 PHP
php iconv() : Detected an illegal character in input string
Dec 05 PHP
PHP数组无限分级数据的层级化处理代码
Dec 29 PHP
php用正则表达式匹配中文实例详解
Nov 06 PHP
php中spl_autoload详解
Oct 17 PHP
php实现ip白名单黑名单功能
Mar 12 PHP
Joomla调用系统自带编辑器的实现方法
May 05 PHP
php获取flash尺寸详细数据的方法
Nov 12 PHP
php使用ftp实现文件上传与下载功能
Jul 21 PHP
PHP实现的折半查找算法示例
Dec 19 PHP
Laravel框架中集成MongoDB和使用详解
Oct 17 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
便携利器 — TECSUN PL-365简评
2021/03/02 无线电
用PHP连接Oracle数据库
2006/10/09 PHP
php数组总结篇(一)
2008/09/30 PHP
php实现网站插件机制的方法
2009/11/10 PHP
php 模拟 asp.net webFrom 按钮提交事件实例
2014/10/13 PHP
Extjs EditorGridPanel中ComboBox列的显示问题
2011/07/04 Javascript
js跨浏览器实现将字符串转化为xml对象的方法
2013/09/25 Javascript
javascript的propertyIsEnumerable()方法使用介绍
2014/04/09 Javascript
Javascript的闭包详解
2014/12/26 Javascript
深入解读JavaScript中的Hoisting机制
2015/08/12 Javascript
jQuery中attr()与prop()函数用法实例详解(附用法区别)
2015/12/29 Javascript
JavaScript:Array类型全面解析
2016/05/19 Javascript
轻松实现jquery选项卡切换效果
2016/10/10 Javascript
微信小程序 教程之模块化
2016/10/17 Javascript
jquery dialog获取焦点的方法
2017/02/09 Javascript
详解vue-cli + webpack 多页面实例应用
2017/04/25 Javascript
微信小程序实现图片压缩功能
2018/01/26 Javascript
mpvue构建小程序的方法(步骤+地址)
2018/05/22 Javascript
Vue 中如何正确引入第三方模块的方法步骤
2019/05/05 Javascript
详解从vue-loader源码分析CSS Scoped的实现
2019/09/23 Javascript
JavaScript使用localStorage存储数据
2019/09/25 Javascript
python异常和文件处理机制详解
2016/07/19 Python
Pandas0.25来了千万别错过这10大好用的新功能
2019/08/07 Python
python TCP包注入方式
2020/05/05 Python
《小石潭记》教学反思
2014/02/13 职场文书
2014最新开业庆典策划方案(5篇)
2014/09/15 职场文书
公安交警中队队长个人对照检查材料思想汇报
2014/10/05 职场文书
医院护士工作检讨书
2014/10/26 职场文书
2014年志愿者工作总结
2014/11/20 职场文书
评职称个人总结
2015/03/05 职场文书
幼儿园教师工作总结2015
2015/04/02 职场文书
银行柜员工作心得体会
2016/01/23 职场文书
2016年党员公开承诺书格式范文
2016/03/24 职场文书
Golang标准库syscall详解(什么是系统调用)
2021/05/25 Golang
React Native项目框架搭建的一些心得体会
2021/05/28 Javascript
Python jiaba库的使用详解
2021/11/23 Python