@@ -25,7 +25,8 @@ until you interact with the proxy in some way.
25
25
26
26
.. caution ::
27
27
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.
29
30
30
31
In PHP versions prior to 8.0 lazy services do not support parameters with
31
32
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:
100
101
over the ``lazy `` flag and directly instantiate the service as it would
101
102
normally do.
102
103
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
+
103
179
Additional Resources
104
180
--------------------
105
181
0 commit comments