@@ -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,77 @@ 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
+ .. 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
+
103
175
Additional Resources
104
176
--------------------
105
177
0 commit comments