资讯专栏INFORMATION COLUMN

Laravel Container (容器) 概念详解 (上)

FullStackDeveloper / 2249人阅读

摘要:上文书,创建对象需要先创建对象。创建对象的杂活是嵌入在中的。对象使用来管理依赖关系非常好,但不是必须的。很容易实现,但手工维护各种乱七八糟的对象还是很麻烦。所有文章均已收录至项目。

本文翻译自 Symfony 作者 Fabien Potencier 的 《Dependency Injection in general and the implementation of a Dependency Injection Container in PHP》 系列文章。

Part 1: What is Dependency Injection?

Part 2: Do you need a Dependency Injection Container?

Part 3: Introduction to the Symfony Service Container

Part 4: Symfony Service Container: Using a Builder to create Services

Part 5: Symfony Service Container: Using XML or YAML to describe Services

Part 6: The Need for Speed

专有名词翻译成中文后会变得不利于理解,后续文章中将改用括号+中文备注的形式。

上文我通过一些示例讲解了 Dependency Injection ,本文将接着介绍 Dependency Injection Containers (容器) 的概念。

首先记住这句话:

大多数时候,Dependency Injection 并不需要 Container

只有当你需要管理一大堆具有很多依赖关系的不同对象时,Container 才会非常有用(例如框架中)。

上文书,创建 User 对象需要先创建 SessionStorate 对象。这里的有个瑕疵,创建对象时需要提前知道它所有的依赖项:

$storage = new SessionStorage("SESSION_ID");
$user = new User($storage);

Zend FrameworkZend_Mail 库发送邮件过程为例:

$transport = new Zend_Mail_Transport_Smtp("smtp.gmail.com", [
  "auth"     => "login",
  "username" => "foo",
  "password" => "bar",
  "ssl"      => "ssl",
  "port"     => 465,
]);

$mailer = new Zend_Mail();
$mailer->setDefaultTransport($transport);

请把这个例子看做一个大系统中的一小部分,因为这种简单的例子当然没必要用 Container

Dependency Injection Container 是一个“知道如何实例化和配置对象”的对象(工厂模式的升华)。为了做到这点,它需要知道构造函数的参数、以及对象之间的关系。

下面是一个写死 Zend_MailContainer

class Container
{
  public function getMailTransport()
  {
    return new Zend_Mail_Transport_Smtp("smtp.gmail.com", [
      "auth"     => "login",
      "username" => "foo",
      "password" => "bar",
      "ssl"      => "ssl",
      "port"     => 465,
    ]);
  }

  public function getMailer()
  {
    $mailer = new Zend_Mail();
    $mailer->setDefaultTransport($this->getMailTransport());

    return $mailer;
  }
}

这个 Container 用起来就相当简单了:

$container = new Container();
$mailer = $container->getMailer();

我们只管向 Containermailer 对象就行,完全不用管 mailer 怎么创建。创建 mailer 对象的“杂活”是嵌入在 Container 中的。
Container 通过 getMailTransport() 方法,把 Zend_Mail_Transport_Smtp 这个依赖自动注入到了 Zend_Mail 中。

细心的网友可能已经发现,这里的 Container 把什么都写死了。我们可以完善一下:

class Container
{
  protected $parameters = array();

  public function __construct(array $parameters = [])
  {
    $this->parameters = $parameters;
  }

  public function getMailTransport()
  {
    return new Zend_Mail_Transport_Smtp("smtp.gmail.com", [
      "auth"     => "login",
      "username" => $this->parameters["mailer.username"],
      "password" => $this->parameters["mailer.password"],
      "ssl"      => "ssl",
      "port"     => 465,
    ]);
  }

  public function getMailer()
  {
    $mailer = new Zend_Mail();
    $mailer->setDefaultTransport($this->getMailTransport());

    return $mailer;
  }
}

现在就可以随时更改 usernamepassword 了:

$container = new Container([
  "mailer.username" => "foo",
  "mailer.password" => "bar",
]);
$mailer = $container->getMailer();

如果需要更改 mailer 类,把类名也当参数传入就行:

class Container
{
  // ...

  public function getMailer()
  {
    $class = $this->parameters["mailer.class"];

    $mailer = new $class();
    $mailer->setDefaultTransport($this->getMailTransport());

    return $mailer;
  }
}

$container = new Container([
  "mailer.username" => "foo",
  "mailer.password" => "bar",
  "mailer.class"    => "Zend_Mail",
]);
$mailer = $container->getMailer();

如果想每次获取同一个 mailer 实例,可以用 单例模式

class Container
{
  static protected $shared = [];

  // ...

  public function getMailer()
  {
    if (isset(self::$shared["mailer"]))
    {
      return self::$shared["mailer"];
    }

    $class = $this->parameters["mailer.class"];

    $mailer = new $class();
    $mailer->setDefaultTransport($this->getMailTransport());

    return self::$shared["mailer"] = $mailer;
  }
}

这就包含了 Dependency Injection Containers 的基本功能:

Container 管理对象实例化到配置的过程

对象本身不知道自己是由 Container 管理的,对 Container 一无所知。

这就是为什么 Container 能够管理任何 PHP 对象。 对象使用 DI 来管理依赖关系非常好,但不是必须的。

Container 很容易实现,但手工维护各种乱七八糟的对象还是很麻烦。下一章我将介绍 LaravelContainer 的实现方式。

作者下一章原文中讲的是 ContainerSymfony 2 中的实现,我会把它换成 Laravel

原创。 所有 Laravel 文章均已收录至 laravel-tips 项目。

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

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

相关文章

  • Laravel Container (容器) 深入理解 (下)

    摘要:意味着依赖被注入进构造函数或者方法如果需要复用实例,可以定义为单例可以用接口或任何名称来代替具体类。技能重写构造函数参数方法允许将附加参数传递给构造函数。 本文大部分翻译自 DAVE JAMES MILLER 的 《Laravel’s Dependency Injection Container in Depth》 。 上文介绍了 Dependency Injection Contai...

    eternalshallow 评论0 收藏0
  • Laravel Dependency Injection (依赖注入) 概念详解

    摘要:依赖注入并不限于构造函数作为经验,注入最适合必须的依赖关系,比如示例中的情况注入最适合可选依赖关系,比如缓存一个对象实例。 本文翻译自 Symfony 作者 Fabien Potencier 的 《Dependency Injection in general and the implementation of a Dependency Injection Container in P...

    Fundebug 评论0 收藏0
  • 深入剖析 Laravel 服务容器

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

    abson 评论0 收藏0
  • Laravel中的核心概念

    摘要:可以为服务提供者的方法设置类型提示。方法将在所有其他服务提供者均已注册之后调用。所有服务提供者都在配置文件中注册。可以选择推迟服务提供者的注册,直到真正需要注册绑定时,这样可以提供应用程序的性能。 本文最早发布于 Rootrl的Blog 导言 Laravel是一款先进的现代化框架,里面有一些概念非常重要。在上手Laravel之前,我认为先弄懂这些概念是很有必要的。你甚至需要重温下PHP...

    ddongjian0000 评论0 收藏0
  • 详解 Laravel 中的依赖注入和 IoC

    摘要:依赖注入依赖注入一词是由提出的术语,它是将组件注入到应用程序中的一种行为。就像说的依赖注入是敏捷架构中关键元素。类依赖于,所以我们的代码可能是这样的创建一个这是一种经典的方法,让我们从使用构造函数注入开始。 showImg(https://segmentfault.com/img/remote/1460000018806800); 文章转自:https://learnku.com/la...

    haitiancoder 评论0 收藏0

发表评论

0条评论

FullStackDeveloper

|高级讲师

TA的文章

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