专栏名称: 唤之
目录
相关文章推荐
待字闺中  ·  DeepSeek 爆火带来的大变化 ·  6 天前  
程序员小灰  ·  DeepSeek创始人梁文峰牛逼的个人经历 ·  昨天  
OSC开源社区  ·  敢自称Java版PyTorch,EasyAi ... ·  2 天前  
OSC开源社区  ·  如何公正评价百度开源的贡献? ·  3 天前  
程序员小灰  ·  如何用DeepSeek来变现?90%的人都不知道 ·  3 天前  
51好读  ›  专栏  ›  唤之

Laravel 服务容器必知必会

唤之  · 掘金  · 程序员  · 2018-04-25 09:55

正文

这是一篇社区协同翻译的文章,已完成翻译,更多信息请点击 协同翻译介绍

file 学习如何用 Laravel 构建一个应用程序,不仅仅是学习使用不同的类和框架中的组件,也不是要记住全部的 artisan 命令或所有的辅助函数(我们有 Google)。学习用 Laravel 编码是学习它的哲学和优雅迷人的语法。 我个人觉得是一件艺术和工艺品(巧合的是 Laravel 工程师有时也被称作 Web 艺术家)。对其他框架这也是真理。 rayle 翻译于 2天前 0 重译 Summer 审阅

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

基础

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

现在我们拥有了一个包含所有绑定对象服务的单一对象( IOC 容器), 因此在我们的代码中,任何时候都可以很容易从这个单一对象中获取或者"解析"这些对象服务

吴彦文 翻译于 2天前 0 重译 JiaZombie 审阅

查看其他 1 个版本

绑定的处理方式

现在假设我们有一个特别功能的 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 一样,用优雅的方式)。

若相惜 翻译于 2天前 0 重译 Summer 审阅

如何绑定 ?

绑定简单得可以用一行代码完成

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

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

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

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

若相惜 翻译于 2天前 0 重译 Summer 审阅

如何解析 ?

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

// 使用IoC 我们可以这么做
$fooService = app()->make('FooService');
$fooService->doSomething();
// 也可以精简为一行代码
app()->make('FooService')->doSomething();

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

冷剑白狐 翻译于 2天前 0 重译 JiaZombie 审阅

在容器中绑定接口

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

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

$this->app->bind(FooInterface::class, FooClass::class);
Jeffrey 翻译于 1天前 0 重译 Summer 审阅 因此,当 FooInterface 被成功解析,Laravel 足够聪明的给我们一个 FooClass 的实例。 现在想象一下我们已经写了一个 FooInterface 的更好的实现叫做 BarClass ,并且我们希望用它替换 FooClass ,我们所需要做的所有事情就是:
$this->app->bind(FooInterface::class, BarClass::class);

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

Jeffrey 翻译于 1天前 0 重译 Summer 审阅

依赖解析

我们知道 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));
Jeffrey 翻译于 1天前 1 重译 Summer 审阅

查看其他 1 个版本







请到「今天看啥」查看全文