您不再(从 Symfony 4 开始)需要创建编译器通道来配置服务定位器。
可以通过配置完成所有事情,让 Symfony 执行“魔法”。
您可以在配置中添加以下内容:
services:
_instanceof:
DriverInterface:
tags: ['app.driver']
lazy: true
DriverConsumer:
arguments:
- !tagged_locator
tag: 'app.driver'
需要访问这些而不是接收 的服务会iterable
接收ServiceLocatorInterface
:
class DriverConsumer
{
private $drivers;
public function __construct(ServiceLocatorInterface $locator)
{
$this->locator = $locator;
}
public function foo() {
$driver = $this->locator->get(Driver::class);
// where Driver is a concrete implementation of DriverInterface
}
}
就是这样。你不需要任何其他东西,它只是工作tm。
完整示例
涉及所有类的完整示例。
我们有:
FooInterface
:
interface FooInterface
{
public function whoAmI(): string;
}
AbstractFoo
为了简化实现,我们将在具体服务中扩展一个抽象类:
abstract class AbstractFoo implements FooInterface
{
public function whoAmI(): string {
return get_class($this);
}
}
服务实现
实现的几个服务FooInterface
class FooOneService extends AbstractFoo { }
class FooTwoService extends AbstractFoo { }
服务的消费者
还有另一个服务需要服务定位器来使用我们刚刚定义的这两个:
class Bar
{
/**
* @var \Symfony\Component\DependencyInjection\ServiceLocator
*/
private $service_locator;
public function __construct(ServiceLocator $service_locator) {
$this->service_locator = $service_locator;
}
public function handle(): string {
/** @var \App\Test\FooInterface $service */
$service = $this->service_locator->get(FooOneService::class);
return $service->whoAmI();
}
}
配置
唯一需要的配置是:
services:
_instanceof:
App\Test\FooInterface:
tags: ['test_foo_tag']
lazy: true
App\Test\Bar:
arguments:
- !tagged_locator
tag: 'test_foo_tag'
服务名称的 FQCN 替代方案
如果您不想使用类名来定义自己的服务名称,则可以使用静态方法来定义服务名称。配置将更改为:
App\Test\Bar:
arguments:
- !tagged_locator
tag: 'test_foo_tag'
default_index_method: 'fooIndex'
其中fooIndex
是在每个返回字符串的服务上定义的公共静态方法。注意:如果使用此方法,您将无法通过类名获取服务。