Skip to content

Commit 089db61

Browse files
committed
Merge branch '4.4' into 5.4
* 4.4: [DI] Document proxifying interfaces for lazy services
2 parents 08b2633 + 37cb398 commit 089db61

File tree

1 file changed

+77
-1
lines changed

1 file changed

+77
-1
lines changed

service_container/lazy_services.rst

Lines changed: 77 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,81 @@ 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+
.. versionadded:: 4.2
115+
116+
Proxyfying interfaces was introduced in Symfony 4.2.
117+
118+
.. configuration-block::
119+
120+
.. code-block:: yaml
121+
122+
# config/services.yaml
123+
services:
124+
App\Twig\AppExtension:
125+
lazy: 'Twig\Extension\ExtensionInterface'
126+
# or a complete definition:
127+
lazy: true
128+
tags:
129+
- { name: 'proxy', interface: 'Twig\Extension\ExtensionInterface' }
130+
131+
.. code-block:: xml
132+
133+
<!-- config/services.xml -->
134+
<?xml version="1.0" encoding="UTF-8" ?>
135+
<container xmlns="http://symfony.com/schema/dic/services"
136+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
137+
xsi:schemaLocation="http://symfony.com/schema/dic/services
138+
https://symfony.com/schema/dic/services/services-1.0.xsd">
139+
140+
<services>
141+
<service id="App\Twig\AppExtension" lazy="Twig\Extension\ExtensionInterface"/>
142+
<!-- or a complete definition: -->
143+
<service id="App\Twig\AppExtension" lazy="true">
144+
<tag name="proxy" interface="Twig\Extension\ExtensionInterface"/>
145+
</service>
146+
</services>
147+
</container>
148+
149+
.. code-block:: php
150+
151+
// config/services.php
152+
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
153+
154+
use App\Twig\AppExtension;
155+
use Twig\Extension\ExtensionInterface;
156+
157+
return function(ContainerConfigurator $configurator) {
158+
$services = $configurator->services();
159+
160+
$services->set(AppExtension::class)
161+
->lazy()
162+
->tag('proxy', ['interface' => ExtensionInterface::class])
163+
;
164+
};
165+
166+
The virtual `proxy`_ injected into other services will only implement the
167+
specified interfaces and will not extend the original service class, allowing to
168+
lazy load services using `final`_ classes. You can configure the proxy to
169+
implement multiple interfaces by adding new "proxy" tags.
170+
171+
.. tip::
172+
173+
This feature can also act as a safe guard: given that the proxy does not
174+
extend the original class, only the methods defined by the interface can
175+
be called, preventing to call implementation specific methods. It also
176+
prevents injecting the dependency at all if you type-hinted a concrete
177+
implementation instead of the interface.
178+
103179
Additional Resources
104180
--------------------
105181

0 commit comments

Comments
 (0)