结论:

  • PHP中提供了反射类来解析类的结构;
  • 通过反射类可以获取到类的构造函数及其参数和依赖;
  • 给构造函数的参数递归设置默认值后,即可使用这些带默认值的参数通过 newInstanceArgs 实例化出类对象;
  • 在实例化的过程中,依赖的类也会被实例化,从而实现了依赖注入。

PHP中反射类的常用方法:

// 通过类名 Circle 实例化反射类
$reflectionClass = new reflectionClass(Circle::class);
// 获取类常量
$reflectionClass->getConstants();
// 获取类属性
$reflectionClass->getProperties();
// 获取类方法
$reflectionClass->getMethods();
// 获取类的构造函数
$constructor = $reflectionClass->getConstructor();
// 获取方法的参数
$parameters = $constructor->getParameters();
// 通过参数默认值数组实例化类创建对象
$class = $reflectionClass->newInstanceArgs($dependencies);

创建两个具有依赖关系的类:

class Point
{
public $x;
public $y; public function __construct($x = 0, $y = 0)
{
$this->x = $x;
$this->y = $y;
}
} class Circle
{
// 圆的半径
public $radius; // 圆心位置
public $center; const PI = 3.14; public function __construct(Point $point, $radius = 1)
{
$this->center = $point;
$this->radius = $radius;
} // 打印圆心位置的坐标
public function printCenter()
{
printf('圆心的位置是:(%d, %d)', $this->center->x, $this->center->y);
} //计算圆形的面积
public function area()
{
return 3.14 * pow($this->radius, 2);
}
}

创建两个方法:

make 方法负责解析类和构建类的对象;

getDependencies 负责依赖解析并初始化参数默认值;

//构建类的对象
function make($className)
{
try {
$reflectionClass = new ReflectionClass($className);
$constructor = $reflectionClass->getConstructor();
$parameters = $constructor->getParameters();
$dependencies = getDependencies($parameters); // 用指定的参数创建一个新的类实例
return $reflectionClass->newInstanceArgs($dependencies);
} catch (ReflectionException $e) {
throw new Exception("{$className} not found.");
}
} //依赖解析并初始化参数默认值
function getDependencies($parameters)
{
$dependencies = [];
// Circle 类的参数为 point 和 radius
// Point 类的参数为 x 和 y
foreach($parameters as $parameter) {
$dependency = $parameter->getClass();
// 如果参数不是类
if (is_null($dependency)) {
// 可选参数,有默认值
if($parameter->isDefaultValueAvailable()) {
$dependencies[] = $parameter->getDefaultValue();
}
// 必传参数暂时先给一个默认值
else {
$dependencies[] = '0';
}
}
// 如果参数是类
else {
// 递归进行依赖解析
$dependencies[] = make($parameter->getClass()->name);
}
} return $dependencies;
}

测试:

// 实例化对象
$circle = make('Circle');
// 调用对象的方法
$area = $circle->area();
var_dump($circle, $area);

过程说明:

make('Circle')
getDependencies(Point, int)
make('Point')
getDependencies(int, int)
new Point(int, int);
return Point;
new Circle(Point, int);
return Circle;

深入 Laravel 内核之 PHP 反射机制和依赖注入的更多相关文章

  1. Spring的反射机制和依赖注入

    我们知道,Spring中大量使用了反射机制,那么究竟是什么地方使用了呢? spring的一大核心概念是注入, 但是,这存在的一个前提就是类是由spring管理起来的. 反射是根据className生成 ...

  2. Spring进阶之路(1)-Spring核心机制:依赖注入/控制反转

    原文地址:http://blog.csdn.net/wangyang1354/article/details/50757098 我们经常会遇到这样一种情景,就是在我们开发项目的时候经常会在一个类中调用 ...

  3. 7 -- Spring的基本用法 -- 3... Spring 的核心机制 : 依赖注入

    7.3 Spring 的核心机制 : 依赖注入 Spring 框架的核心功能有两个. Spring容器作为超级大工厂,负责创建.管理所有的Java对象,这些Java对象被称为Bean. Spring容 ...

  4. (转)Spring读书笔记-----Spring核心机制:依赖注入

    Java应用(从applets的小范围到全套n层服务端企业应用)是一种典型的依赖型应用,它就是由一些互相适当地协作的对象构成的.因此,我们说这些对象间存在依赖关系.加入A组件调用了B组件的方法,我们就 ...

  5. Spring核心机制:依赖注入

    转载:http://www.cnblogs.com/chenssy/ Java应用(从applets的小范围到全套n层服务端企业应用)是一种典型的依赖型应用,它就是由一些互相适当地协作的对象构成的.因 ...

  6. Spring读书笔记-----Spring核心机制:依赖注入

    spring框架为我们提供了三种注入方式,分别是set注入,构造方法注入,接口注入.今天就和大家一起来学习一下 依赖注入的基本概念 依赖注入(Dependecy Injection),也称为IoC(I ...

  7. laravel服务容器(IOC控制反转,DI依赖注入),服务提供者,门脸模式

    laravel的核心思想: 服务容器: 容器:就是装东西的,laravel就是一个个的对象 放入:叫绑定 拿出:解析 使用容器的目的:这里面讲到的是IOC控制反转,主要是靠第三方来处理具体依赖关系的解 ...

  8. Spring学习-spring核心机制-IOC依赖注入

    转载自:http://www.cnblogs.com/chenssy/archive/2012/11/11/2765266.html 今天复习一下spring两大特性之一:IOC依赖注入,看了一下大佬 ...

  9. Spring-----3、Spring的核心机制(依赖注入)

    转载自:http://blog.csdn.net/hekewangzi/article/details/41345237

随机推荐

  1. 实现将rsyslog将日志记录与MySQL中

    准备两个节点 node3:  rsyslog node2:   数据库 准备相应的包 [root@node3 php-fpm.d]#yum install rsyslog-mysql 将数据拷贝到数据 ...

  2. supervise安装与使用

    确认当前是否已经安装which supervise/usr/local/bin/supervise 软件下载安装-------------------------------------------- ...

  3. 【Linux】【Shell】【Basic】字符串操作

    1. 字符串切片:             ${var:offset:number}                 取字符串的子串:                 取字符趾的最右侧的几个字符:${ ...

  4. Vue重要知识

    Event Bus 总线 Vue中的EventBus是一种发布订阅模式的实践,适用于跨组件简单通信. Vuex也可以用来组件中进行通信,更适用于多组件高频率通信. 使用方式: 1.把Bus注入到Vue ...

  5. 赋能开发:捷码携手达内教育打造IT职业教育新生态

    近日,达内教育与远眺科技签约联合培养的第一批低代码开发方向的高职学生,在杭州未来科技城捷码总部顺利毕业,首期合格学员总数超过30名.随着这些接受了"捷码"低代码平台全程" ...

  6. TSN(时间敏感网络)测试、仿真、分析平台应用攻略

    前言 在汽车领域,近几年车内网络通讯方式的变革诉求,期望能够有更高的数据传输速率,以及保证实时性的通讯方式引入.例如对于ADAS而言,传统的CAN总线已经远远不能满足其对通讯的要求,而基于车载以太网的 ...

  7. SWPUCTF 2019 pwn writeup

    来做一下以前比赛的题目,下面两个题目都可以在buu复现(感谢赵总). SWPUCTF_2019_login 32位程序,考点是bss段上的格式化字符串.用惯onegadgets了,而对于32位程序来说 ...

  8. Office365与Office2016差异汇总

    以下很多链接来自原来的博客,如果有哪篇"被色情"的,请留言联系我,谢谢! 2020-8-29更新 通用 图片透明度:http://blog.sina.com.cn/s/blog_5 ...

  9. 复杂SQL案例:用户授权渠道查询

    供参考: SELECT r.course_id 课程id, r.user_id 用户ID, u.user_full_name 姓名, u.province_name 省名, u.city_name 城 ...

  10. IDEA版本2020.1全局MAVEN配置

    我们用IDEA打开项目有时候要每次配置maven地址,这样就很麻烦 我们可以直接设置全局的 这样所有新打开的项目都能使用