Skip to content

Commit 1bcb34e

Browse files
committed
Merge branch '5.4' into 6.0
* 5.4: [DI] Document proxifying interfaces for lazy services
2 parents 9802e6d + 85708a2 commit 1bcb34e

File tree

1 file changed

+73
-1
lines changed

1 file changed

+73
-1
lines changed

service_container/lazy_services.rst

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ until you interact with the proxy in some way.
2525

2626
.. caution::
2727

28-
Lazy services do not support `final`_ classes.
28+
Lazy services do not support `final`_ classes, but you can use
29+
`Interface Proxifying`_ to work around this limitation.
2930

3031
In PHP versions prior to 8.0 lazy services do not support parameters with
3132
default values for built-in PHP classes (e.g. ``PDO``).
@@ -100,6 +101,77 @@ To check if your proxy works you can check the interface of the received object:
100101
over the ``lazy`` flag and directly instantiate the service as it would
101102
normally do.
102103

104+
Interface Proxifying
105+
--------------------
106+
107+
Under the hood, proxies generated to lazily load services inherit from the class
108+
used by the service. However, sometimes this is not possible at all (e.g. because
109+
the class is `final`_ and can not be extended) or not convenient.
110+
111+
To workaround this limitation, you can configure a proxy to only implement
112+
specific interfaces.
113+
114+
.. configuration-block::
115+
116+
.. code-block:: yaml
117+
118+
# config/services.yaml
119+
services:
120+
App\Twig\AppExtension:
121+
lazy: 'Twig\Extension\ExtensionInterface'
122+
# or a complete definition:
123+
lazy: true
124+
tags:
125+
- { name: 'proxy', interface: 'Twig\Extension\ExtensionInterface' }
126+
127+
.. code-block:: xml
128+
129+
<!-- config/services.xml -->
130+
<?xml version="1.0" encoding="UTF-8" ?>
131+
<container xmlns="http://symfony.com/schema/dic/services"
132+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
133+
xsi:schemaLocation="http://symfony.com/schema/dic/services
134+
https://symfony.com/schema/dic/services/services-1.0.xsd">
135+
136+
<services>
137+
<service id="App\Twig\AppExtension" lazy="Twig\Extension\ExtensionInterface"/>
138+
<!-- or a complete definition: -->
139+
<service id="App\Twig\AppExtension" lazy="true">
140+
<tag name="proxy" interface="Twig\Extension\ExtensionInterface"/>
141+
</service>
142+
</services>
143+
</container>
144+
145+
.. code-block:: php
146+
147+
// config/services.php
148+
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
149+
150+
use App\Twig\AppExtension;
151+
use Twig\Extension\ExtensionInterface;
152+
153+
return function(ContainerConfigurator $configurator) {
154+
$services = $configurator->services();
155+
156+
$services->set(AppExtension::class)
157+
->lazy()
158+
->tag('proxy', ['interface' => ExtensionInterface::class])
159+
;
160+
};
161+
162+
The virtual `proxy`_ injected into other services will only implement the
163+
specified interfaces and will not extend the original service class, allowing to
164+
lazy load services using `final`_ classes. You can configure the proxy to
165+
implement multiple interfaces by adding new "proxy" tags.
166+
167+
.. tip::
168+
169+
This feature can also act as a safe guard: given that the proxy does not
170+
extend the original class, only the methods defined by the interface can
171+
be called, preventing to call implementation specific methods. It also
172+
prevents injecting the dependency at all if you type-hinted a concrete
173+
implementation instead of the interface.
174+
103175
Additional Resources
104176
--------------------
105177

0 commit comments

Comments
 (0)