/**
* 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 = , $y = )
{
$this->x = $x;
$this->y = $y;
}
}
class Circle
{
/**
* @var int
*/
public $radius;//半径 /**
* @var Point
*/
public $center;//圆心点 const PI = 3.14; public function __construct(Point $point, $radius = )
{
$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, );
}
}

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() {
[]=>
object(ReflectionProperty)# () {
["name"]=>
string() "radius"
["class"]=>
string() "Circle"
}
[]=>
object(ReflectionProperty)# () {
["name"]=>
string() "center"
["class"]=>
string() "Circle"
}
}

反射出类中定义的方法

$reflectionClass->getMethods();

  

返回ReflectionMethod对象构成的数组

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[] = '';
}
} else {
//递归解析出依赖类的对象
$dependencies[] = make($parameter->getClass()->name);
}
} return $dependencies;
}

定义好make方法后我们通过它来帮我们实例化Circle类的对象:

$circle = make('Circle');
$area = $circle->area();
var_dump($area);
$areas = $circle->printCenter();
var_dump($areas);

  

float(3.14)
center coordinate is (0, 0)

  

PHP类的反射和依赖注入的更多相关文章

  1. ThinkPHP6源码:从Http类的实例化看依赖注入是如何实现的

    ThinkPHP 6 从原先的 App 类中分离出 Http 类,负责应用的初始化和调度等功能,而 App 类则专注于容器的管理,符合单一职责原则. 以下源码分析,我们可以从 App,Http 类的实 ...

  2. 添加EF上下文对象,添加接口、实现类以及无处不在的依赖注入(DI)

    添加EF上下文对象,添加接口.实现类以及无处不在的依赖注入(DI) 目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 上一章,我们介绍了安装和新建控制器.视图,这一章我们来创建 ...

  3. laravel中如何利用反射实现依赖注入

    依赖注入 在一个类中经常会依赖于其他的对象,先看一下经典的写法 class Foo { public $bar; public function __construct() { $this->b ...

  4. 【无私分享:ASP.NET CORE 项目实战(第二章)】添加EF上下文对象,添加接口、实现类以及无处不在的依赖注入(DI)

    目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 上一章,我们介绍了安装和新建控制器.视图,这一章我们来创建个数据模型,并且添加接口和实现类. 添加EF上下文对象 按照我们以前 ...

  5. 第四节:配置的读取、StartUp类、内置依赖注入和扩展改造

    一. 配置的读取 在Asp.Net Core中,有一个 appsettings.json 文件,用于存储相应的配置信息,读取的时,要通过构造函数注入:IConfiguration Configurat ...

  6. Java反射及依赖注入简单模拟

    一.编写Dao类 ? 1 2 3 4 5 6 7 8 9 10 11 package cn.com.songjy.annotation;   import java.util.Date;   publ ...

  7. 【Java】利用注解和反射实现一个"低配版"的依赖注入

    在Spring中,我们可以通过 @Autowired注解的方式为一个方法中注入参数,那么这种方法背后到底发生了什么呢,这篇文章将讲述如何用Java的注解和反射实现一个“低配版”的依赖注入. 下面是我们 ...

  8. DI容器Ninject在管理接口和实现、基类和派生类并实现依赖注入方面的实例

    当一个类依赖于另一个具体类的时候,这样很容易形成两者间的"强耦合"关系.我们通常根据具体类抽象出一个接口,然后让类来依赖这个接口,这样就形成了"松耦合"关系,有 ...

  9. 转 Autofac怎么依赖注入ASP.NET MVC5类的静态方法

    之前我有介绍过怎么在ASP.NET mvc5中实现的Controller的依赖注入.一般是通过Contrller的构造函数的参数或者属性来注入,但是这有一个共同点就是调用这个类的方法一般都是实例方法, ...

随机推荐

  1. DBC文件小结

    Vector的DBC文件描述了CAN网络的通信规范,通过定义signal可以表示CAN帧中的各个物理信号的含义.通过CANdb++ Editor软件可以创建和修改DBC文件,一般监控或控制CAN网络内 ...

  2. Replica Set + sharding搭建mongodb集群

    先上几个用到的yaml文件,以后有时间了再更新,我是借鉴的https://blog.csdn.net/zeroctu/article/details/71082168,本人按照上面的搭建,是可行的,不 ...

  3. flask框架----整合Flask中的目录结构

    一.SQLAlchemy-Utils 由于sqlalchemy中没有提供choice方法,所以借助SQLAlchemy-Utils组件提供的choice方法 import datetime from ...

  4. 单点登录系统和CAS的简介

    ---恢复内容开始--- 什么是单点登录? 单点登录(Single Sign On),简称为SSO,是目前比较流行的企业业务整合的解决方案之一.SSO的定义是在多个应用系统中,用户只需要登录一次就可以 ...

  5. MySQL中show profiles的开启

    Query Profiler是MYSQL自带的一种query诊断分析工具,通过它可以分析出一条SQL语句的性能瓶颈在什么地方.通常我们是使用的explain,以及slow query log都无法做到 ...

  6. springboot-yml内list、map组合写法

    yml:myProps: varmaplist: key11: - t1 - t2 - t3 key22: - t11 - t22 - t33 list: - topic1 - topic2 - to ...

  7. MySQL文档翻译(八)附英文原文---性能优化概览

    优化概述 数据库性能表现依赖于数据库级别的几个因素,比如表,查询和配置设置.这些软件在硬件级别通过CPU和IO操作构筑结果,你需要尽可能的使用最少的资源达到最大的效果.当你专注于数据库的性能表现时,你 ...

  8. Java集合中的细节

    integer数据对比 对于Integer var = ? 在-128至127范围内的赋值,Integer对象是在IntegerCache.cache产生,会复用已有对象,这个区间内的Integer值 ...

  9. D9 图论综合题

    1.白银莲花池 LUOGU 2411 第一种思路:当然我们可以写三个bfs a掉这个题,这写下来一二百行要有了吧: 第二种:我们可以在一个bfs中维护所有的信息,一个方向数组,从起点开始,向八个方向扩 ...

  10. OpenCV自带dnn的Example研究(1)— classification

    这个博客系列,简单来说,今天我们就是要研究 https://docs.opencv.org/master/examples.html下的 6个文件,看看在最新的OpenCV中,它们是如何发挥作用的. ...