@@ -105,6 +105,112 @@ working with optional dependencies. It is also more difficult to use in
105105combination with class hierarchies: if a class uses constructor injection
106106then extending it and overriding the constructor becomes problematic.
107107
108+ Immutable-setter Injection
109+ --------------------------
110+
111+ .. versionadded :: 4.3
112+
113+ The ``immutable-setter `` injection was introduced in Symfony 4.3.
114+
115+ Another possible injection is to use a method which returns a separate instance
116+ by cloning the original service, this approach allows you to make a service immutable::
117+
118+ // ...
119+ use Symfony\Component\Mailer\MailerInterface;
120+
121+ class NewsletterManager
122+ {
123+ private $mailer;
124+
125+ /**
126+ * @required
127+ * @return static
128+ */
129+ public function withMailer(MailerInterface $mailer)
130+ {
131+ $new = clone $this;
132+ $new->mailer = $mailer;
133+
134+ return $new;
135+ }
136+
137+ // ...
138+ }
139+
140+ In order to use this type of injection, don't forget to configure it:
141+
142+ .. configuration-block ::
143+
144+ .. code-block :: yaml
145+
146+ # config/services.yaml
147+ services :
148+ # ...
149+
150+ app.newsletter_manager :
151+ class : App\Mail\NewsletterManager
152+ calls :
153+ - [withMailer, ['@mailer'], true]
154+
155+ .. code-block :: xml
156+
157+ <!-- config/services.xml -->
158+ <?xml version =" 1.0" encoding =" UTF-8" ?>
159+ <container xmlns =" http://symfony.com/schema/dic/services"
160+ xmlns : xsi =" https://www.w3.org/2001/XMLSchema-instance"
161+ xsi : schemaLocation =" http://symfony.com/schema/dic/services
162+ https://symfony.com/schema/dic/services/services-1.0.xsd" >
163+
164+ <services >
165+ <!-- ... -->
166+
167+ <service id =" app.newsletter_manager" class =" App\Mail\NewsletterManager" >
168+ <call method =" withMailer" returns-clone =" true" >
169+ <argument type =" service" id =" mailer" />
170+ </call >
171+ </service >
172+ </services >
173+ </container >
174+
175+ .. code-block :: php
176+
177+ // config/services.php
178+ use App\Mail\NewsletterManager;
179+ use Symfony\Component\DependencyInjection\Reference;
180+
181+ // ...
182+ $container->register('app.newsletter_manager', NewsletterManager::class)
183+ ->addMethodCall('withMailer', [new Reference('mailer')], true);
184+
185+ .. note ::
186+
187+ If you decide to use autowiring, this type of injection requires
188+ that you add a ``@return static `` docblock in order for the container
189+ to be capable of registering the method.
190+
191+ This approach is useful if you need to configure your service according to your needs,
192+ so, here's the advantages of immutable-setters:
193+
194+ * Immutable setters works with optional dependencies, this way, if you don't need
195+ a dependency, the setter don't need to be called.
196+
197+ * Like the constructor injection, using immutable setters force the dependency to stay
198+ the same during the lifetime of a service.
199+
200+ * This type of injection works well with traits as the service can be composed,
201+ this way, adapting the service to your application requirements is easier.
202+
203+ * The setter can be called multiple times, this way, adding a dependency to a collection
204+ becomes easier and allows you to add a variable number of dependencies.
205+
206+ The disadvantages are:
207+
208+ * As the setter call is optional, a dependency can be null during execution,
209+ you must check that the dependency is available before calling it.
210+
211+ * Unless the service is declared lazy, it is incompatible with services
212+ that reference each other in what are called circular loops.
213+
108214Setter Injection
109215----------------
110216
@@ -180,6 +286,9 @@ This time the advantages are:
180286 the method adds the dependency to a collection. You can then have a variable
181287 number of dependencies.
182288
289+ * Like the immutable-setter one, this type of injection works well with
290+ traits and allows you to compose your service.
291+
183292The disadvantages of setter injection are:
184293
185294* The setter can be called more than just at the time of construction so
0 commit comments