如何使用配置器配置服务
服务配置器是服务容器的一个特性,它允许您使用可调用对象在服务实例化后配置服务。
例如,当您的服务需要基于来自不同来源/服务的配置设置进行复杂设置时,可以使用服务配置器。使用外部配置器,您可以保持服务实现的清晰,并使其与提供所需配置的其他对象解耦。
另一个用例是当您有多个对象共享通用配置,或者应该在运行时以类似方式配置时。
例如,假设您有一个应用程序,您向用户发送不同类型的电子邮件。电子邮件通过不同的格式化程序传递,这些格式化程序可以根据一些动态应用程序设置启用或禁用。您开始定义一个 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;
}
}
如果您的目标是避免将 NewsletterManager
和 GreetingCardManager
与 EmailFormatterManager
耦合,那么您可能希望创建一个配置器类来配置这些实例
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
的工作是将启用的格式化程序注入到 NewsletterManager
和 GreetingCardManager
中,因为它们不知道启用的格式化程序来自哪里。另一方面,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\NewsletterManager
或 App\Mail\GreetingCardManager
服务时,创建的实例将首先传递给 EmailConfigurator::configure()
方法。