php 依赖注入 反射,依赖注入、控制反转、反射各个概念的理解和使用

依赖注入、控制反转、反射各个概念的理解和使用

由 cxp1539 创建于2年前, 最后更新于 2年前

版本号 #1

9980 views

18 likes

1 collects

概念理解

我们先来介绍控制反转,依赖注入,这两个概念我们可以认为他们表达的同一种意思,举个通俗的例子,我们用户登录需要提供记录日志的功能,可以选择使用文件或者数据库。下面我们用代码来演示。

// 定义写日志的接口规范

interface log

{

public function write();

}

// 文件记录日志

class FileLog implements Log

{

public function write(){

echo 'file log write...';

}

}

// 数据库记录日志

class DatabaseLog implements Log

{

public function write(){

echo 'database log write...';

}

}

// 程序操作类

class User

{

protected $fileLog;

public function __construct()

{

$this->fileLog = new FileLog();

}

public function login()

{

// 登录成功,记录登录日志

echo 'login success...';

$this->fileLog->write();

}

}

$user = new User();

$user->login();

上面的写法可以实现记录日志的功能,但是有一个问题,假设现在想用数据库记录日志的话,我们就得修改User类,这份代码没达到解耦合,也不符合编程开放封闭原则,那如何修改呢?我们可以把日志处理类通过构造函数方式传递进去。下面我们试着修改User类的代码。

class User

{

protected $log;

public function __construct(Log $log)

{

$this->log = $log;

}

public function login()

{

// 登录成功,记录登录日志

echo 'login success...';

$this->log->write();

}

}

$user = new User(new DatabaseLog());

$user->login();

这样想用任何方式记录操作日志都不需要去修改过User类了,只需要通过构造函数参数传递就可以实现,其实这就是“控制反转”。不需要自己内容修改,改成由外部外部传递。这种由外部负责其依赖需求的行为,我们可以称其为 “控制反转(IoC)”。

那什么是依赖注入呢?,其实上面的例子也算是依赖注入,不是由自己内部new对象或者实例,通过构造函数,或者方法传入的都属于依赖注入(DI) 。

依赖注入

初学laravel的同学应该都比较好奇?很多对象实例通过方法参数定义就能传递进来,调用的时候不需要我们自己去手动传入。下面举一个laravel中实际的例子 Request对象 会都被自动的注入到函数里。是不是比较好奇呢?laravel是如何做到呢?

// routes/web.php

Route::get('/post/store', 'PostController@store');

// App\Http\Controllers

class PostController extends Controller {

public function store(Illuminate\Http\Request $request)

{

$this->validate($request, [

'category_id' => 'required',

'title' => 'required|max:255|min:4',

'body' => 'required|min:6',

]);

}

}

反射理解

我们现在已经明白了依赖注入的概念。那laravel那种用法怎么实现呢?可能有些同学已经想到了这里面肯定会用到反射机制去创建动态Post,然后去调用store方法。

反射的概念其实可以理解成根据类名返回该类的任何信息,比如该类有什么方法,参数,变量等等。我们先来学习下反射要用到的api。拿User举例

// 获取User的reflectionClass对象

$class = new reflectionClass(User::class);

// 拿到User的构造函数

$constructor = $class->getConstructor();

// 拿到User的构造函数的所有依赖参数

$dependencies = $constructor->getParameters();

// 创建user对象

$user = $reflector->newInstance();

// 创建user对象,需要传递参数的

$user = $reflector->newInstanceArgs($dependencies = []);

这时候我们可以创建一个make方法,传入User,利用反射机制拿到User的构造函数,进而得到构造函数的参数对象。用递归的方式创建参数依赖。最后调用newInstanceArgs方法生成User实例。 可能有些同学还不是很理解。下面我们用代码去简单模拟下

function make(concrete){

// 或者User的反射类

$reflector = new ReflectionClass($concrete);

// User构造函数

$constructor = $reflector->getConstructor();

// User构造函数参数

$dependencies = $constructor->getParameters();

// 最后生成User

return $reflector->newInstanceArgs($dependencies);

}

$user = make('User');

$user->login();

具体代码实现

// 注意我们这里需要修改一下User的构造函数,如果不去修改。反射是不能动态创建接口的,那如果非要用接口该怎么处理呢?下一节我们讲Ioc容器的时候会去解决。

class User

{

protected $log;

public function __construct(FileLog $log)

{

$this->log = $log;

}

public function login()

{

// 登录成功,记录登录日志

echo 'login success...';

$this->log->write();

}

}

function make($concrete){

$reflector = new ReflectionClass($concrete);

$constructor = $reflector->getConstructor();

// 为什么这样写的? 主要是递归。比如创建FileLog不需要传入参数。

if(is_null($constructor)) {

return $reflector->newInstance();

}else {

// 构造函数依赖的参数

$dependencies = $constructor->getParameters();

// 根据参数返回实例,如FileLog

$instances = $this->getDependencies($dependencies);

return $reflector->newInstanceArgs($instances);

}

}

function getDependencies($paramters) {

$dependencies = [];

foreach ($paramters as $paramter) {

$dependencies[] = make($paramter->getClass()->name);

}

return $dependencies;

}

$user = make('User');

$user->login();

到这里,我们依赖注入,控制翻转,反射也就讲完了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值