liip / container-wrapper-bundle
因为妈妈教你不要通过注入一切来搞砸依赖注入。
Requires
- php: ^5.3.9|^7.0
- symfony/dependency-injection: ~2.3
- symfony/framework-bundle: ~2.3
This package is not auto-updated.
Last update: 2022-02-01 12:20:13 UTC
README
此包不再维护。如有需要,请随意分叉。
ContainerWrapperBundle
因为不要通过注入一切来搞砸依赖注入。
此包是为那些不喜欢容器注入但被迫使用它的人准备的。它提供了一个可配置的代理容器,仅公开实际容器的一部分,或重新定义某些服务。您可以选择注入此包装器而不是完整容器,从而对组件的依赖关系拥有更细粒度的控制。
1. It provides an abstract ``liip_container_wrapper.service`` service to extend from.
2. It provides a way to easy set default service and parameters to map
3. It can replace itself with an alias to ``service_container`` via a config
option as long as no service/parameter is mapped to a different id/name
安装
1. Install with Composer
`php composer.phar require liip/container-wrapper-bundle`
2. Add this bundle to your application's kernel:
// application/ApplicationKernel.php
public function registerBundles()
{
return array(
// ...
new Liip\ContainerWrapperBundle\LiipContainerWrapperBundle(),
// ...
);
}
配置
默认服务和参数可以在应用程序配置中配置。将 disable_optimization
设置为 true 将在所有未使用映射的情况下移除 ContainerWrapper 服务,以使用 service_container
的别名。
# app/config.yml
liip_container_wrapper:
services:
templating: acme_hello.templating
parameters:
kernel.debug: true
disable_optimization: %kernel.debug%
services
和 parameters
都配置为键值对。键是从该特定 ContainerWrapper
实例可访问的 id 名称。值可以是 true
或不同服务或参数的 id 名称。在非 true
值的情况下,id 名称将映射到另一个 id 名称。
以上例子
// will return an instance of the 'acme_hello.templating' service
$container->get('templating');
// will return an the value of the 'kernel.debug' parameter
$container->getParameter('kernel.debug');
请注意,由于 templating
映射到不同的服务 id,将 disable_optimization
设置为 false
将没有任何效果,因为普通的 Container
实例无法支持为 templating
设置不同的别名。
示例使用
以下 YAML 配置扩展了 liip_container_wrapper.service
抽象服务,以定义一个 acme_hello.container
服务,可以注入替换 Container
实例,限制对在包配置中以及在此配置中定义的服务和参数的访问。
acme_hello.foo.controller:
class: Acme\HelloBundle\Controller\FooController
calls:
- ['setContainer', [ @acme_hello.container ] ]
acme_hello.container:
parent: liip_container_wrapper.service
arguments:
index_0:
some_service: true
拯救小猫的故事
为什么哦为什么?
是的,为什么有人会麻烦设置一个漂亮的依赖注入容器,然后浪费其所有的好处,只注入整个容器,从而实际上使他们的代码依赖于 DI 容器中配置的几乎所有内容?我敢肯定,上帝每次都会杀死几只小猫...
除了小猫之外,注入容器还会防止对依赖关系的细粒度调整。也就是说,控制器 Blabla 需要注入与控制器 DingDing 不同的模板化服务,但如果你在两处代码中都使用 $this->container->get('templating')
,你怎么做?向上帝祈祷不是答案,他正忙着杀死小猫呢。
而且,那些足够疯狂去关心单元测试的人也会很快意识到,将他们想要注入的所有内容都包裹在一个容器模拟对象中,甚至更没有乐趣。
哦,没有经过繁琐步骤的IDE自动补全支持也是注入容器的一个重大遗憾,或者有哪个IDE能解析你的DIC来确定$this->container->get('i_hate_kittens')
返回的是什么?
但是,还有许多糟糕的答案,比如懒惰等等,仍然可以注入DIC,但有三条半可接受的理由
-
有人编写了有用的代码,但认为强制注入整个DIC是一个很好的主意
-
有相当一部分可选依赖,它们并不能通过拆分服务(实际上有两个)来解决,这也是为什么即使是由好人编写的代码也会发生这种情况的原因)。
-
你需要注入一个服务,然后服务才能存在,比如Symfony2中的请求服务
但是,等等,还有希望!
在这些情况下,你现在有办法防止小猫咪被杀害了!
相反,你可以使用ContainerWrapper来显式配置你的依赖关系,并将硬编码的服务ID映射回来,以恢复由于没有显式注入依赖而失去的灵活性。
但是,参数!
是的,参数也由包装器处理,尽管它们并没有从延迟加载论点中受益多少,但我猜一旦开发者走上了黑暗的道路,他可能会继续使用DI容器而不是显式注入参数,所以,可能也应该添加参数支持。邪恶在邪恶的道路上如此富有创造力。