服务容器...翻译中

3.4 版本
维护中的版本

你的程序 全部是 各有用途的对象: 一个 "Mailer" 对象可以帮助你发送邮件,而另一个对象可以帮你把数据入库。 你程序中的几乎 所有 事都是由这些对象中的某一个来完成的。每当你安装一个新bundle,你就拥有了更多的对象!

在Symfony中,这些有用的对象被称为 services(服务),每一个服务都被存放于一个特殊的名为 service container(服务容器)之中。如果你有服务容器,那么你可以使用服务的id来取出服务:

1
2
$logger = $container->get('logger');
$entityManager = $container->get('doctrine.orm.entity_manager');

容器让你把对象的组织方式中心化。它节省你的时间,提升至强力架构,而且巨快!

取得并使用服务 

从你开启 Symfony 程序那一刻起,你的容器 已经 包含了许多服务。很像是 工具 : 等待着你利用 它们。在控制器中,你可以借助“服务的类名或接口名”来对action的参数进行 type-hinting 以“请求”容器中的服务。想要 log 一些东西?没有问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// src/AppBundle/Controller/ProductController.php
// ...
 
use Psr\Log\LoggerInterface;
 
/**
 * @Route("/products")
 */
public function listAction(LoggerInterface $logger)
{
    $logger->info('Look! I just used a service');
 
    // ...
}

3.3 新功能: Symfony 3.3 增加了“对服务进行type-hint以便取得它”的能力。参考控制器章节以了解更多。

还有什么服务可以利用?运行以下命令,找出它们:

1
$  php bin/console debug:container

下面是输出结果的小型示例:

Service ID Class name
doctrine Doctrine\Bundle\DoctrineBundle\Registry
filesystem Symfony\Component\Filesystem\Filesystem
form.factory Symfony\Component\Form\FormFactory
logger Symfony\Bridge\Monolog\Logger
request_stack Symfony\Component\HttpFoundation\RequestStack
router Symfony\Bundle\FrameworkBundle\Routing\Router
security.authorization_checker Symfony\Component\Security\Core\Authorization\AuthorizationChecker
security.password_encoder Symfony\Component\Security\Core\Encoder\UserPasswordEncoder
session Symfony\Component\HttpFoundation\Session\Session
translator Symfony\Component\Translation\DataCollectorTranslator
twig Twig_Environment
validator Symfony\Component\Validator\Validator\ValidatorInterface

你也可以使用唯一的 "Service ID" 来直接访问服务:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// src/AppBundle/Controller/ProductController.php
namespace AppBundle\Controller;
 
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
 
class ProductController extends Controller
{
    /**
     * @Route("/products")
     */
    public function listAction()
    {
        $logger = $this->container->get('logger');
        $logger->info('Look! I just used a service');
 
        // ...
    }
}

像这样直接从容器中取出服务 只在你继承了 Controller 类时才能运行。

在这篇文档中,你将看到如何使用容器中的各种不同的服务。

Container: Lazy-loaded for speed

Wait! Are all the services (objects) instantiated on every request? No! The container is lazy: it doesn't instantiate a service until (and unless) you ask for it. For example, if you never use the validator service during a request, the container will never instantiate it.

在容器中创建/配置服务 

Tip

The recommended way of configuring services changed in Symfony 3.3. For a deep explanation, see The Symfony 3.3 DI Container Changes Explained (autowiring, _defaults, etc).

You can also organize your own code into services. For example, suppose you need to show your users a random, happy message. If you put this code in your controller, it can't be re-used. Instead, you decide to create a new class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// src/AppBundle/Service/MessageGenerator.php
namespace AppBundle\Service;
 
class MessageGenerator
{
    public function getHappyMessage()
    {
        $messages = [
            'You did it! You updated the system! Amazing!',
            'That was one of the coolest updates I\'ve seen all day!',
            'Great work! Keep going!',
        ];
 
        $index = array_rand($messages);
 
        return $messages[$index];
    }
}

注入服务/配置成一个服务 

处理多个服务 

手动关联参数 

服务参数(Parameters) 

选择一个特殊服务 

Autowire自动关联选项 

Autoconfigure自动配置选项 

Public vs Private服务 

使用resource一次导入多个服务 

显式配置服务及其参数 

本文,包括例程代码在内,采用的是 Creative Commons BY-SA 3.0 创作共用授权。

登录symfonychina 发表评论或留下问题(我们会尽量回复)