@@ -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 ``).
@@ -87,5 +88,76 @@ To check if your lazy service works you can check the interface of the received
87
88
dump(class_implements($service));
88
89
// the output should include "Symfony\Component\VarExporter\LazyGhostObjectInterface"
89
90
91
+ Interface Proxifying
92
+ --------------------
93
+
94
+ Under the hood, proxies generated to lazily load services inherit from the class
95
+ used by the service. However, sometimes this is not possible at all (e.g. because
96
+ the class is `final `_ and can not be extended) or not convenient.
97
+
98
+ To workaround this limitation, you can configure a proxy to only implement
99
+ specific interfaces.
100
+
101
+ .. configuration-block ::
102
+
103
+ .. code-block :: yaml
104
+
105
+ # config/services.yaml
106
+ services :
107
+ App\Twig\AppExtension :
108
+ lazy : ' Twig\Extension\ExtensionInterface'
109
+ # or a complete definition:
110
+ lazy : true
111
+ tags :
112
+ - { name: 'proxy', interface: 'Twig\Extension\ExtensionInterface' }
113
+
114
+ .. code-block :: xml
115
+
116
+ <!-- config/services.xml -->
117
+ <?xml version =" 1.0" encoding =" UTF-8" ?>
118
+ <container xmlns =" http://symfony.com/schema/dic/services"
119
+ xmlns : xsi =" http://www.w3.org/2001/XMLSchema-instance"
120
+ xsi : schemaLocation =" http://symfony.com/schema/dic/services
121
+ https://symfony.com/schema/dic/services/services-1.0.xsd" >
122
+
123
+ <services >
124
+ <service id =" App\Twig\AppExtension" lazy =" Twig\Extension\ExtensionInterface" />
125
+ <!-- or a complete definition: -->
126
+ <service id =" App\Twig\AppExtension" lazy =" true" >
127
+ <tag name =" proxy" interface =" Twig\Extension\ExtensionInterface" />
128
+ </service >
129
+ </services >
130
+ </container >
131
+
132
+ .. code-block :: php
133
+
134
+ // config/services.php
135
+ namespace Symfony\Component\DependencyInjection\Loader\Configurator;
136
+
137
+ use App\Twig\AppExtension;
138
+ use Twig\Extension\ExtensionInterface;
139
+
140
+ return function(ContainerConfigurator $configurator) {
141
+ $services = $configurator->services();
142
+
143
+ $services->set(AppExtension::class)
144
+ ->lazy()
145
+ ->tag('proxy', ['interface' => ExtensionInterface::class])
146
+ ;
147
+ };
148
+
149
+ The virtual `proxy `_ injected into other services will only implement the
150
+ specified interfaces and will not extend the original service class, allowing to
151
+ lazy load services using `final `_ classes. You can configure the proxy to
152
+ implement multiple interfaces by adding new "proxy" tags.
153
+
154
+ .. tip ::
155
+
156
+ This feature can also act as a safe guard: given that the proxy does not
157
+ extend the original class, only the methods defined by the interface can
158
+ be called, preventing to call implementation specific methods. It also
159
+ prevents injecting the dependency at all if you type-hinted a concrete
160
+ implementation instead of the interface.
161
+
90
162
.. _`ghost object` : https://en.wikipedia.org/wiki/Lazy_loading#Ghost
91
163
.. _`final` : https://www.php.net/manual/en/language.oop5.final.php
0 commit comments