44Service Locators
55================
66
7- What is a Service Locator
8- -------------------------
9-
10- Sometimes, a service needs the ability to access other services without being sure
11- that all of them will actually be used.
12-
13- In such cases, you may want the instantiation of these services to be lazy, that is
14- not possible using explicit dependency injection since services are not all meant to
7+ Sometimes, a service needs access to several other services without being sure
8+ that all of them will actually be used. In those cases, you may want the
9+ instantiation of the services to be lazy. However, that's not possible using
10+ the explicit dependency injection since services are not all meant to
1511be ``lazy `` (see :doc: `/service_container/lazy_services `).
1612
17- A real-world example being a CommandBus which maps command handlers by Command
18- class names and use them to handle their respective command when it is asked for::
13+ A real-world example are applications that implement the `Command pattern `_
14+ using a CommandBus to map command handlers by Command class names and use them
15+ to handle their respective command when it is asked for::
1916
2017 // ...
2118 class CommandBus
@@ -45,11 +42,9 @@ class names and use them to handle their respective command when it is asked for
4542 // ...
4643 $commandBus->handle(new FooCommand());
4744
48- Because only one command is handled at a time, other command handlers are not
49- used but unnecessarily instantiated.
50-
51- A solution allowing to keep handlers lazily loaded could be to inject the whole
52- dependency injection container::
45+ Considering that only one command is handled at a time, instantiating all the
46+ other command handlers is unnecessary. A possible solution to lazy-load the
47+ handlers could be to inject the whole dependency injection container::
5348
5449 use Symfony\Component\DependencyInjection\ContainerInterface;
5550
@@ -74,20 +69,19 @@ dependency injection container::
7469 }
7570 }
7671
77- But injecting the container has many drawbacks including:
72+ However, injecting the entire container is discouraged because it gives too
73+ broad access to existing services and it hides the actual dependencies of the
74+ services.
7875
79- - too broad access to existing services
80- - services which are actually useful are hidden
76+ ** Service Locators ** are intended to solve this problem by giving access to a
77+ set of predefined services while instantiating them only when actually needed.
8178
82- Service Locators are intended to solve this problem by giving access to a set of
83- identified services while instantiating them only when really needed.
79+ Defining a Service Locator
80+ --------------------------
8481
85- Configuration
86- -------------
87-
88- For injecting a service locator into your service(s), you first need to register
89- the service locator itself as a service using the `container.service_locator `
90- tag:
82+ First, define a new service for the service locator. Use its ``arguments ``
83+ option to include as many services as needed to it and add the
84+ ``container.service_locator `` tag to turn it into a service locator:
9185
9286.. configuration-block ::
9387
@@ -138,11 +132,10 @@ tag:
138132
139133 .. note ::
140134
141- The services defined in the service locator argument must be keyed.
142- Those keys become their unique identifier inside the locator.
143-
135+ The services defined in the service locator argument must include keys,
136+ which later become their unique identifiers inside the locator.
144137
145- Now you can use it in your services by injecting it as needed :
138+ Now you can use the service locator injecting it in any other service :
146139
147140.. configuration-block ::
148141
@@ -183,13 +176,14 @@ Now you can use it in your services by injecting it as needed:
183176
184177 .. tip ::
185178
186- You should create and inject the service locator as an anonymous service if
187- it is not intended to be used by multiple services
179+ If the service locator is not intended to be used by multiple services, it's
180+ better to create and inject it as an anonymous service.
188181
189182Usage
190183-----
191184
192- Back to our CommandBus which now looks like::
185+ Back to the previous CommandBus example, it looks like this when using the
186+ service locator::
193187
194188 // ...
195189 use Psr\Container\ContainerInterface;
@@ -225,3 +219,5 @@ which implements the PSR-11 ``ContainerInterface``, but it is also a callable::
225219 $handler = $locateHandler($commandClass);
226220
227221 return $handler->handle($command);
222+
223+ .. _`Command pattern` : https://en.wikipedia.org/wiki/Command_pattern
0 commit comments