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

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面试怎么实现反射注入的详细内容,更多请关注我们其它相关文章!

(0)

相关推荐

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

    PHP具有完整的反射API,提供了对类.接口.函数.方法和扩展进行逆向工程的能力.通过类的反射提供的能力我们能够知道类是如何被定义的,它有什么属性.什么方法.方法都有哪些参数,类文件的路径是什么等很重要的信息.正是因为类的反射,很多PHP框架才能实现依赖注入自动解决类与类之间的依赖关系,这给我们平时的开发带来了很大的方便. 本文主要是讲解如何利用类的反射来实现依赖注入(Dependency Injection),并不会去逐条讲述PHP Reflection里的每一个API.为了更好地理解,我们通

  • Java Spring项目国际化(i18n)详细方法与实例

    Spring国际化概述 国际化基本规则 国际化信息"也称为"本地化信息",一般需要两个条件才可以确定一个特定类型的本地化信息,它们分别是"语言类型"和"国家/地区的类型".如中文本地化信息既有中国大陆地区的中文,又有中国台湾.中国香港地区的中文,还有新加坡地区的中文.Java通过java.util.Locale类表示一个本地化对象,它允许通过语言参数和国家/地区参数创建一个确定的本地化对象. 语言参数使用ISO标准语言代码表示,这些代码

  • Intellij IDEA如何去掉@Autowired 注入警告的方法

    问题 在Service层注入Mybatis的Mapper我们通常会使用@Autowired 自动注入 @Autowired private ProductMapper productMapper; 但是这样Intellij IDEA会显示红色告警,提示不能自动注入. 当我们在Controller层注入Service时我们也经常直接在Filed上使用@Autowired 注解,这时候不显示红色警告,但是也显示Field injection is not recommended 的建议 原因 第一种

  • 在C++中反射调用.NET的方法(二)

    反射调用返回复杂对象的.NET方法 定义数据接口 上一篇在C++中反射调用.NET(一)中,我们简单的介绍了如何使用C++/CLI并且初步使用了反射调用.NET程序集的简单方法,今天我们看看如何在C++与.NET程序集之间传递复杂对象. 先看看.NET程序集的一个返回对象的方法: public IUserInfo GetUserByID(int userId) { IUserInfo userinfo= EntityBuilder.CreateEntity<IUserInfo>(); user

  • 在C++中反射调用.NET的方法(一)

    为什么要在C++中调用.NET 一般情况下,我们常常会在.NET程序中调用C/C++的程序,使用P/Invoke方式进行调用,在编写代码代码的时候,首先要导入DLL文件,然后在根据C/C++的头文件编写特殊的C#平台调用代码,例如像下面这个样子: [DllImport("Interop.dll",EntryPoint = "Multiply",CharSet = CharSet.Ansi)] static extern int Multiply(int factor

  • java通过反射创建对象并调用方法

    这篇文章主要介绍了java通过反射创建对象并调用方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1.用户类 package com.lf.entity; import com.lf.annotation.SetProperty; import com.lf.annotation.SetTable; public class UserEntity { private String userName; private int userAge;

  • Java反射及性能详细

    目录 一.准备 二.反射调用流程 1.反射的使用 2.getMethod 和 getDeclaredMethod区别 三.调用反射方法 四.反射效率低的原因 五.反射优化 我们今天不探讨框架层面的内容,暂且认为90%的框架不存在无法容忍的性能问题.在做系统调优的过程中,面对随处可见的invoke调用,我的内心其实是比较抵触的,倒不是说反射怎么不好,对于优雅的源码来说,反射必不可少,个人抵触的原因主要是因为反射把真实的方法"隐藏"的很好,面对长长的线程栈比较头大而已.而且我心里一直有个大

  • java操作elasticsearch详细方法总结

    目录 一.前言 二.java操作es的常用模式 三.rest-api 操作 1.前置准备 2.索引相关操作api的使用 2.1  创建索引 2.2  获取索引 2.3  删除索引 3.文档常用操作api的使用 3.1  索引添加文档 3.2  修改文档 3.3  删除文档 3.4  批量添加文档 3.5  批量删除 4.文档搜索相关api的使用 4.1  查询某个索引下的所有数据 4.2  批量查询多条数据 4.3  根据条件精准查询 4.4  分页查询 4.5  查询结果按照某个字段进行排序

  • Java反射使用的详细介绍(最新推荐)

    目录 反射 反射基本介绍 反射获取类对象 反射获取构造器对象 反射获取成员变量对象 反射获取方法对象 反射 反射基本介绍 反射概述: 反射认为类的每一个成份都是一个对象, 对于任何一个Class类,在"运行的时候"都可以直接得到这个类全部成分. 在运行时,可以直接得到这个类的构造器对象:Constructor 在运行时,可以直接得到这个类的成员变量对象:Field 在运行时,可以直接得到这个类的成员方法对象:Method 这种运行时动态获取类信息以及动态调用类中成分的能力称为Java语

  • Spring IOC推导与DI构造器注入超详细讲解

    目录 了解准备 IOC思想 IOC本质 XML配置Spring IOC创建对象方式 了解准备 什么是Spring? Spring是一款轻量级的控制反转(IOC)和面向切面编程(AOP)的非入侵式开源框架 2002年Spring的前身interface21发布,随后在2004年3月24日正式更名发布Spring1.0版本 Spring Frameword缔造者 Rod Johnson,悉尼大学音乐学博士生 Spring框架主要由七部分组成,分别是 Spring Core. Spring AOP.

随机推荐