资讯专栏INFORMATION COLUMN

Laravel深入学习2 - 控制反转容器

worldligang / 2840人阅读

摘要:控制反转容器控制反转使依赖注入变得更加便捷。有瑕疵控制反转容器是实现的控制翻转容器的一种替代方案。容器的独立使用即使没有使用框架,我们仍然可以在项目中使用安装组件来使用的控制反转容器。在没有给定任何信息的情况下,容器是无法实例化相关依赖的。

声明:本文并非博主原创,而是来自对《Laravel 4 From Apprentice to Artisan》阅读的翻译和理解,当然也不是原汁原味的翻译,能保证90%的原汁性,另外因为是理解翻译,肯定会有错误的地方,欢迎指正。

欢迎转载,转载请注明出处,谢谢!

控制反转容器 基础绑定

上一张,我们学习了依赖注入,接下来,我们继续探索的是“控制反转”或者叫“依赖倒置”。后面我们使用IoC容器来代指如上的定义。IoC容器使类的依赖管理变的非常方便,Laravel的核心就是由这种强大的容器思想来驱动的。IoC容器是Laravel框架重要的组成部分,他将框架中所有组件组织在一起工作。事实上Laravel的Application类就是集成自Container容器类。

控制反转容器(IoC Container)

控制反转使依赖注入变得更加便捷。如果在容器中定义好了相关的类或者接口(约定),我们如何在程序中解析、并注入这些对象呢?

Laravel应用中,IoC容器可以使用依照门面设计模式实现的App类来访问容器。容器中包含了各式各样的方法,这里我们只介绍一些比较基础的方法。让我们以上一章中的BillerInterfaceBillingNotifierInterface为基础,来继续探讨使用Stripe1实现的支付功能。我们可以将Stripe的接口实现按照如下代码绑定到容器中:

App::bind("BillerInterface", function()
{
    return new StripeBiller(App::make("BillingNotifierInterface"));
})

注意这里,我们在绑定了BillerInterface的同时,也注入了BillingNotifierInterface接口实现的具体类,所以要将接口绑定到容器中:

App::bind("BillingNotifierInterface", function()
{
    return new EmailBillingNotifier;
});

如上,我们可以理解,容器就是各种接口对应实现类的绑定的地方。一旦他们绑定到容器中,我们就能在整个应用中的任意地方解析并使用他。我们甚至可以在解析器中继续将其他内容绑定到容器。

有瑕疵?

Laravel控制反转容器是Fabien Potencier实现的Pimple2控制翻转容器的一种替代方案。如果你已经在项目中使用到Pimple,尽可安心的升级为Illuminate Container3组件,他为您提供了更多好用的特性!

一旦使用了容器,切换接口实现就是一件非常简单的事情,简单到一行代码就能搞定:

class UserController extends BaseController{

    public function __construct(BillerInterface $biller)
    {
        $this->biller = $biller;
    }
}

控制器通过容器实例化后,包含EmailBillingNotifierStripeBiller类就会随着容器注入到控制器中。现在,若想更换通知器的实现方式,只需要接口绑定的实现即可:

App::bind("BillingNotifierInterface", function()
{
    return new SmsBillingNotifier;
});

现在,无需担心项目中到底哪里用到了这个通知器,只需实现新的SmsBillingNotifier类即可。利用这种方式,我们的应用可以在不同的场景下实现快速切换。

是不是感觉这种切换实现的方式很高大上。想象一下,如果想将短信通知器的服务提供商更换为Twilio。我们只须开发一个使用Twilio通知的实现类,并替换掉绑定到容器中的接口对应的实现类就好。如果在向Twilio的过度中出现了问题,我们还能快速的将容器中接口绑定的类替换回原来的服务,这里只需要那么一丁点改变就能快速实现需求变更。可以看到,依赖注入的优点是超乎想象的。再多几个例子?

好吧!接着往下看。 有时候,我们想在整个应用中对一个类只进行一次解析,一次实例化。使用容器中的singleton方法即可:

App::singleton("BillingNotifierInterface", function()
{
    return new SmsBillingNotifier;
});

现在,容器一蛋解析了订单通知类,在接下来的整个请求中都会使用同一个已实例化的实例。

容器中的intance方法和singleton有点类似;区别在于你可以传入一个已存在的对象来更新接口绑定的实例,在后续的使用中,容器都将使用到这个新的对象。

$notifier = new SmsBillingNotifier;
App::instance("BillingNotifierInterface", $notifier);

现在我们已经熟悉使用容器进行闭包回调的基础方法,接下来,让我们深入挖掘下他更强大的功能:反射。

容器的独立使用

即使没有使用Laravel框架,我们仍然可以在项目中使用Composer安装illuminate/container组件来使用Laravel的控制反转容器。

反射

Laravel容器的一个强大的特性就是能通过反射自动解析依赖。反射具有检测类及其方法的能力。比如,PHP中的ReflectionClass类允许你检测一些方法在给定的类中是否可用。PHP函数method_exists也是反射的一种形式。看看下面的代码,让我们来把玩一下:

$reflection = new ReflectionClass("StripeBiller");

var_dump($reflection->getMethods());

var_dump($reflection->getConstants());

通过使用PHP的这种特性,Laravel可以实现一些有趣的功能!例如,如下代码:

class UserController extends BaseController {

    public function __construct(StripeBiller $biller)
    {
        $this->biller = $biller;
    }

}

如上控制器初始化时需要传入StripeBiller类型的对象,我们可以通过反射进行类型检测。当Laravel容器没有绑定相应的解析器,它就会通过反射尝试解析该类。流程大致如下:

容器中有无StripeBiller解析器?

没有解析器?映射类StripeBiller判断其依赖。

递归的解析StripeBiller类的所有依赖。

通过ReflectionClass->newInstanceArgs()实例化一个新的StripeBiller

可以看到,容器为你做了很多繁重的工作,使你能释放更多的时间用于编码各种逻辑的代码类。这就是Laravel容器特有的强大特性,也是它能够胜任构建大型应用的必杀器。

现在,我们控制器中的代码修改成这样,这会怎样?

class UserController extends BaseController
{
    public function __construct(BillerInterface $biller)
    {
        $this->biller = $biller;
    }
}

假如我们没有对BillerInterface进行绑定,那么容器如何注入其依赖的类呢?注意,接口只是个约定,他是不能进行实例化的。在没有给定任何信息的情况下,容器是无法实例化相关依赖的。所以我们需要使用bind方法来为接口指定一个默认的类的实现:

App::bind("BillerInterface","StripBiller");

这里我们把字符串替换成一个闭包传入容器,他会告诉容器任何情况下总是使用StripeBiller这个实现自BillerInterface接口的类。这里,我们又可以只修改一行代码,就能进行替换掉容器中的绑定的逻辑了。假如我们想使用余额支付来代替现有的支付,我们只需要完成继承自BillerInterface接口的实现类BalanceInterfacez,同时修改下容器中的绑定:

App::bind("BillerInterface", "BalancedBiller");

应用就会自动解析并使用这个新的支付方式。

同样我们也可以使用singleton方法绑定接口,这样在整个请求周期内容器只会进行一次实例化。

App::singleton("BillerInterface", "StripeBiller");

掌握容器

想要深入理解Laravel容器?那就通读下代码吧!容器只有一个类文件IlluminateContainerContainer。当你看完这个文件代码后,肯定能对容器有更深、更全面的认识。

-

2015-04-02 第二次阅读修正。

2015-02-14 第一次翻译发布。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/22562.html

相关文章

  • 深入剖析 Laravel 服务容器

    摘要:划下重点,服务容器是用于管理类的依赖和执行依赖注入的工具。类的实例化及其依赖的注入,完全由服务容器自动的去完成。 本文首发于 深入剖析 Laravel 服务容器,转载请注明出处。喜欢的朋友不要吝啬你们的赞同,谢谢。 之前在 深度挖掘 Laravel 生命周期 一文中,我们有去探究 Laravel 究竟是如何接收 HTTP 请求,又是如何生成响应并最终呈现给用户的工作原理。 本章将带领大...

    abson 评论0 收藏0
  • 深入理解控制反转(IoC)和依赖注入(DI)

    摘要:本文一大半内容都是通过举例来让读者去理解什么是控制反转和依赖注入,通过理解这些概念,来更加深入。这种由外部负责其依赖需求的行为,我们可以称其为控制反转。工厂模式,依赖转移当然,实现控制反转的方法有几种。 容器,字面上理解就是装东西的东西。常见的变量、对象属性等都可以算是容器。一个容器能够装什么,全部取决于你对该容器的定义。当然,有这样一种容器,它存放的不是文本、数值,而是对象、对象的描...

    HollisChuang 评论0 收藏0
  • 深入理解IoC(控制反转)、DI(依赖注入)

    摘要:引述最近看设计模式以及代码,对于控制反转以及依赖注入这些概念非常困惑,于是找了一些资料,以下是对于控制反转的一下理解。其中最常见的方式叫做依赖注入,简称,还有一种方式叫依赖查找。在软件工程中,依赖注入是种实现控制反转用于解决依赖性设计模式。 引述 最近看设计模式以及laravel代码,对于控制反转以及依赖注入这些概念非常困惑,于是找了一些资料,以下是对于控制反转的一下理解。 概念 Io...

    xcc3641 评论0 收藏0
  • php实现依赖注入(DI)和控制反转(IOC)

    摘要:工厂模式,依赖转移当然,实现控制反转的方法有几种。其实我们稍微改造一下这个类,你就明白,工厂类的真正意义和价值了。虽然如此,工厂模式依旧十分优秀,并且适用于绝大多数情况。 此篇文章转载自laravel-china,chongyi的文章https://laravel-china.org/top...原文地址: http://www.insp.top/learn-lar... ,转载务必保...

    tomato 评论0 收藏0
  • Laravel 服务容器实现原理

    摘要:框架中就是使用服务容器来实现控制反转和依赖注入。容器依赖注入的实现实现原理需要了解的知识点闭包匿名函数匿名函数,也叫闭包函数,允许临时创建一个没有指定名称的函数反射以上版本具有完整的反射,添加了对类接口函数方法和扩展进行反向工程的能力。 前言 通过实现laravel 框架功能,以便深入理解laravel框架的先进思想。 什么是服务容器 服务容器是用来管理类依赖与运行依赖注入的工具。La...

    wupengyu 评论0 收藏0

发表评论

0条评论

worldligang

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<