New in Symfony 3.3: Service locators

In Symfony applications, some services need access to several other services
although some of them will not be actually used (e.g. the FirewallMap
class). Instantiating all those unused services is useless, but it's not
possible to turn them into lazy services using explicit dependency injection.

The traditional solution in those cases was to inject the entire service
container to get only the services really needed. However, this is not
recommended because it gives services a too broad access to the rest of the
application and it hides the actual dependencies of the services.

Service locators are a design pattern that "encapsulate the processes involved
in obtaining a service [...] using a central registry known as the service locator".
This pattern is often discouraged, but it's useful in these cases and it's way
better than injecting the entire service container.

Consider a CommandBus class that maps commands and their handlers. This class
handles only one command at a time, so it's useless to instantiate all of them.
First, define a service locator service with the new container.service_locator
tag and add all the commands as arguments:

The injected service locator is an instance of Symfony\Component\DependencyInjection\ServiceLocator.
This class implements the PSR-11 ContainerInterface, which includes the
has() and get() methods to check and get services from the locator:

// ...usePsr\Container\ContainerInterface;classCommandBus{/** @var ContainerInterface */private$handlerLocator;// ...publicfunctionhandle(Command$command){$commandClass=get_class($command);// check if some service is included in the service locatorif(!$this->handlerLocator->has($commandClass)){return;}// get the service from the service locator (and instantiate it)$handler=$this->handlerLocator->get($commandClass);return$handler->handle($command);}}

In the case of simple dependency call, you can define a service who call the specific service needed, that's easy and autowiring is not needed anymore.

I've always said that allowing to access the service container inside the services.yml file is a bad idea, I prefer to use private service to restrict the call capacities of the controllers and type the service that I need from one service to another.

For me, it seems that this solution allow a factory service who return many services, who's a bad idea (because well, the service container allow the same approach in some circumstances), in my opinion, the factory service contains the whole services injected declarations and this way, all the service who need this factory service has access to the method like if the service was injected manually by the services.yml.

For the special case of a command, I rather prefer to inject only the service that I need directly in the services.yml definition rather than using a "factory" who inject for me :/

Do you think it is feasible to pass a lambda, which has the service locator bound, so when the lambda gets executed it will return the service object? If not executed then nothing happens all all is lazy.

@Max ContainerAware = injecting the DIC, a DIC is not meant to be injected into services but to inject things into them. A service locator is meant to be injected, and the class scope is identifiable through the services its locator has access to.

@Loulier This feature solves a very specific need that your domain should not have. Yes, a locator gives access to several services, but they are all identified.