Laravel 服务容器必知必会

文章转发自专业的Laravel开发者社区,原始连接: https://learnku.com/laravel/t...

学习如何用 Laravel 构建一个应用程序,不只仅是学习使用不一样的类和框架中的组件,也不是要记住所有的 artisan 命令或全部的辅助函数(咱们有 Google)。学习用 Laravel 编码是学习它的哲学和优雅迷人的语法。 我我的以为是一件艺术和工艺品(巧合的是 Laravel 工程师有时也被称做 Web 艺术家)。对其余框架这也是真理。php

服务容器和 IOC 容器是 Laravel 哲学的主要部分。做为一个 Laravel 开发者,理解并能正确的使用服务容器是你掌握它的重要部分, 由于它是任何 Laravel 应用的核心。laravel

基础

虽然 IOC 容器本质上只是一个普通的 PHP 类, 可是我喜欢将它看作"袋中的技巧"。 这个"袋子"就是咱们放置或者"绑定"任何咱们须要运行在 Laravel 应用中的对象服务, 从接口实现到目录路径以及其余等等。所以叫作"袋中的技巧"编程

如今咱们拥有了一个包含全部绑定对象服务的单一对象( IOC 容器), 所以在咱们的代码中,任什么时候候均可以很容易的从这个单一对象中获取或者"解析"这些对象服务app

绑定的处理方式

如今假设咱们有一个特别功能的 FooService 类。框架

<?php
namespace App\Services;
class FooService
{
    public function __construct()
    {
        ...
    }
    public function doSomething()
    {
        // Code for Something.
    }
}

若是咱们要调用类的 doSomething 方法,咱们可能会这样作 :函数

$fooService = new \App\Services\FooService();\
$fooService->doSomething();

这看起来没有什么问题,但比较麻烦的是这儿的 'new' 关键字,个人意思是虽然这样也很好,可是咱们能够作的更优雅 (记住写代码要像 Laravel 同样,用优雅的方式)。学习

如何绑定 ?

绑定简单得能够用一行代码完成测试

$this->app->bind('FooService', \App\Services\FooService::class);

在 Laravel 中咱们常说:“把 FooService 服务巧妙的注入到包中”。this

固然根据使用场景和服务方式,也有其余的方法来绑定服务,只要你理解它的基本思想。有关绑定的完整参考,能够查阅 Laravel 的文档 服务容器编码

须要注意的是,服务必须绑定到服务提供商的注册方法中。

如何解析 ?

当服务绑定到容器以后, 咱们能够在应用中的任何地方获取或者解析服务.

// 使用IoC 咱们能够这么作
$fooService = app()->make('FooService');
$fooService->doSomething();
// 也能够精简为一行代码
app()->make('FooService')->doSomething();

咱们只须要告诉 Laravel : "记住 FooService, 当我须要时把它给我." 你注意到了吗? 用 IoC 建立服务让代码更简洁, 明了, 易读. 这就是 Laravel 的优雅之处, 而且会使你的代码更易于测试, 由于当你测试时你可使用一个伪造的类去替换 FooService (我以为你应该很熟悉怎么在测试中伪造类).

在容器中绑定接口

在面向对象编程中,接口是建立一些必须遵循某种规划或者约束的类的一种方法。这能帮助其余开发者建立与您的接口中设置的约束相匹配的代码。这强制他们传递合法的参数给函数而且返回特定的数据类型,尽管他们的方法的实现可能有所不一样。经过这种方式,您能够轻松的肯定继承相同接口的不一样实现将以相同的方式工做。

在 Laravel 的容器中咱们可以绑定一个特定的接口的实现,经过这种方式,当咱们解析这个接口时,咱们最终会获得绑定到它的具体类。

$this->app->bind(FooInterface::class, FooClass::class);

所以,当 FooInterface 被成功解析,Laravel 足够聪明的给咱们一个 FooClass 的实例。

如今想象一下咱们已经写了一个 FooInterface 的更好的实现叫作 BarClass,而且咱们但愿用它替换 FooClass,咱们所须要作的全部事情就是:

$this->app->bind(FooInterface::class, BarClass::class);

咱们的代码依旧正常运行由于咱们知道 BarClass 会遵循咱们的接口,就算 BarClass 和预期的表现不一致咱们也能够切换回 FooClass 。这是一种很好的方法,能在没有太多回归(regressions)的状况下升级应用的代码。

依赖解析

咱们知道 Laravel 可以解析咱们在容器中绑定的服务和接口,可是它能作的不只仅是这些。事实上,它还能在咱们一行代码都不写的状况下自动为咱们解析这些服务的依赖。

想象一下咱们的项目中有下面这些服务类。

<?php
class BarService 
{
  /**
   * 要作的事情。
   * 
   * @return string
   */
  public function somethingToDo()
  {
    return 'I am doing something';
  }
}
<?php
class FooService 
{
  /**
   * BarService 实例.
   * 
   * @var BarService
   */
  protected $bar;
  
  /**
   * 建立新的 FooService 实例
   * 
   * @param BarService $bar
   */
  public function __construct(BarService $bar)
  {
    $this->bar = $bar;
  }
  
  /**
   * 作点有用的事
   * 
   * @return string
   */
  public function doSomething()
  {
    return $this->bar->somethingToDo();
  }
}

咱们能看到 FooService 须要一个 BarService 的实例。咱们怎么才能把它绑定到容器中这样当 Laravel 给咱们一个 FooService 的实例时它也会给咱们一个BarService 的实例?

你或许会想这个解决方法可能会是下面这样:

$this->app->bind('Foo', new FooService(new BarService));

从技术上来讲,这是能够实现的,但实际上咱们不须要这样作。 Laravel 经过使用 PHP 强大的反射特性,自动就为咱们解决了这个问题。所以,你只须要像往常那样绑定就好:

$this->app->bind('Foo', FooService::class);

如今,当代码解析到 Foo 时, Laravel 将会去寻找 FooService 服务,当发现它须要一个 BarService 服务的实例; Laravel 又将会去寻找 BarService 服务,并将它实例化以后的对象提供给 FooService 服务的构造函数,从而为咱们建立一个完整的实例。这些过程不须要咱们写一行代码,真的是十分惊艳而又清晰的思路!!

除此以外,上述过程将会提供给全部的依赖。因此,若是 BarService 服务也有本身的依赖,那么也会经过上述的方式来解决。

最后的话

关于 Laravel 的服务容器还有许多很棒的事情须要讨论和学习。我但愿这个小介绍能给你一些启发并帮助你加深对容器的理解。

我鼓励你经过阅读文档了解更多  [docs]
( https://laravel.com/docs/5.6/... )。

感谢你的阅读。

相关文章
相关标签/搜索