跳到内容

如何使用配置器配置服务

编辑此页

服务配置器是服务容器的一个特性,它允许您使用可调用对象在服务实例化后配置服务。

例如,当您的服务需要基于来自不同来源/服务的配置设置进行复杂设置时,可以使用服务配置器。使用外部配置器,您可以保持服务实现的清晰,并使其与提供所需配置的其他对象解耦。

另一个用例是当您有多个对象共享通用配置,或者应该在运行时以类似方式配置时。

例如,假设您有一个应用程序,您向用户发送不同类型的电子邮件。电子邮件通过不同的格式化程序传递,这些格式化程序可以根据一些动态应用程序设置启用或禁用。您开始定义一个 NewsletterManager 类,如下所示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// src/Mail/NewsletterManager.php
namespace App\Mail;

class NewsletterManager implements EmailFormatterAwareInterface
{
    private array $enabledFormatters;

    public function setEnabledFormatters(array $enabledFormatters): void
    {
        $this->enabledFormatters = $enabledFormatters;
    }

    // ...
}

以及 GreetingCardManager

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// src/Mail/GreetingCardManager.php
namespace App\Mail;

class GreetingCardManager implements EmailFormatterAwareInterface
{
    private array $enabledFormatters;

    public function setEnabledFormatters(array $enabledFormatters): void
    {
        $this->enabledFormatters = $enabledFormatters;
    }

    // ...
}

如前所述,目标是在运行时根据应用程序设置设置格式化程序。为此,您还需要一个 EmailFormatterManager 类,它负责加载和验证应用程序中启用的格式化程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// src/Mail/EmailFormatterManager.php
namespace App\Mail;

class EmailFormatterManager
{
    // ...

    public function getEnabledFormatters(): array
    {
        // code to configure which formatters to use
        $enabledFormatters = [...];

        // ...

        return $enabledFormatters;
    }
}

如果您的目标是避免将 NewsletterManagerGreetingCardManagerEmailFormatterManager 耦合,那么您可能希望创建一个配置器类来配置这些实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// src/Mail/EmailConfigurator.php
namespace App\Mail;

class EmailConfigurator
{
    public function __construct(
        private EmailFormatterManager $formatterManager,
    ) {
    }

    public function configure(EmailFormatterAwareInterface $emailManager): void
    {
        $emailManager->setEnabledFormatters(
            $this->formatterManager->getEnabledFormatters()
        );
    }

    // ...
}

EmailConfigurator 的工作是将启用的格式化程序注入到 NewsletterManagerGreetingCardManager 中,因为它们不知道启用的格式化程序来自哪里。另一方面,EmailFormatterManager 掌握了有关启用的格式化程序以及如何加载它们的知识,从而保持了单一职责原则。

提示

虽然此示例使用 PHP 类方法,但配置器可以是任何有效的 PHP 可调用对象,包括函数、静态方法和服务的方法。

使用配置器

您可以使用 configurator 选项配置服务配置器。如果您使用的是 默认的 services.yaml 配置,则所有类都已作为服务加载。您需要做的就是指定 configurator

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# config/services.yaml
services:
    # ...

    # Registers all 4 classes as services, including App\Mail\EmailConfigurator
    App\:
        resource: '../src/*'
        # ...

    # override the services to set the configurator
    App\Mail\NewsletterManager:
        configurator: ['@App\Mail\EmailConfigurator', 'configure']

    App\Mail\GreetingCardManager:
        configurator: ['@App\Mail\EmailConfigurator', 'configure']

服务可以通过可调用配置器(用 __invoke() 替换 configure() 方法)进行配置,方法是省略方法名称

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# config/services.yaml
services:
    # ...

    # registers all classes as services, including App\Mail\EmailConfigurator
    App\:
        resource: '../src/*'
        # ...

    # override the services to set the configurator
    App\Mail\NewsletterManager:
        configurator: '@App\Mail\EmailConfigurator'

    App\Mail\GreetingCardManager:
        configurator: '@App\Mail\EmailConfigurator'

就是这样!当请求 App\Mail\NewsletterManagerApp\Mail\GreetingCardManager 服务时,创建的实例将首先传递给 EmailConfigurator::configure() 方法。

这项工作,包括代码示例,根据 Creative Commons BY-SA 3.0 许可证获得许可。
目录
    版本