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

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

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

首先记住这句话:

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

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

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

$storage = new SessionStorage('SESSION_ID');

$user = new User($storage);

以 Zend Framework 中 Zend_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_Mail 的 Container:

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();

我们只管向 Container 要 mailer 对象就行,完全不用管 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;

}

}

现在就可以随时更改 username 和 password 了:

$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 很容易实现,但手工维护各种乱七八糟的对象还是很麻烦。下一章我将介绍 Laravel 中 Container 的实现方式。

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

本作品采用《CC 协议》,转载必须注明作者和本文链接

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值