@@ -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 ``).
@@ -87,5 +88,76 @@ To check if your lazy service works you can check the interface of the received
8788 dump(class_implements($service));
8889 // the output should include "Symfony\Component\VarExporter\LazyGhostObjectInterface"
8990
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+
90162.. _`ghost object` :https://en.wikipedia.org/wiki/Lazy_loading#Ghost
91163.. _`final` :https://www.php.net/manual/en/language.oop5.final.php