4
4
Service Locators
5
5
================
6
6
7
- What is a Service Locator
8
- -------------------------
9
-
10
- Sometimes, a service needs the ability to acce
10000
ss 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
15
11
be ``lazy `` (see :doc: `/service_container/lazy_services `).
16
12
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::
19
16
20
17
// ...
21
18
class CommandBus
@@ -45,11 +42,9 @@ class names and use them to handle their respective command when it is asked for
45
42
// ...
46
43
$commandBus->handle(new FooCommand());
47
44
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::
53
48
54
49
use Symfony\Component\DependencyInjection\ContainerInterface;
55
50
@@ -74,20 +69,19 @@ dependency injection container::
74
69
}
75
70
}
76
71
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.
78
75
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.
81
78
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
+ --------------------------
84
81
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:
91
85
92
86
.. configuration-block ::
93
87
@@ -138,11 +132,10 @@ tag:
138
132
139
133
.. note ::
140
134
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.
144
137
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 :
146
139
147
140
.. configuration-block ::
148
141
@@ -183,13 +176,14 @@ Now you can use it in your services by injecting it as needed:
183
176
184
177
.. tip ::
185
178
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.
188
181
189
182
Usage
190
183
-----
191
184
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::
193
187
194
188
// ...
195
189
use Psr\Container\ContainerInterface;
@@ -225,3 +219,5 @@ which implements the PSR-11 ``ContainerInterface``, but it is also a callable::
225
219
$handler = $locateHandler($commandClass);
226
220
227
221
return $handler->handle($command);
222
+
223
+ .. _`Command pattern` : https://en.wikipedia.org/wiki/Command_pattern
0 commit comments