@@ -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+
103179Additional Resources
104180--------------------
105181
0 commit comments