From f86b97693b3afbb3f0d023fc10b253aae8c1a942 Mon Sep 17 00:00:00 2001 From: Tugdual Saunier Date: Wed, 3 Aug 2022 12:39:37 -0400 Subject: [PATCH] [DI] Document proxifying interfaces for lazy services Symfony 4.2 introduced the possibility to lazy load services using final classes by proxyfying specific interfaces, but this has not been documented yet. --- service_container/lazy_services.rst | 78 ++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/service_container/lazy_services.rst b/service_container/lazy_services.rst index 0370e52b0ff..ed83a302df3 100644 --- a/service_container/lazy_services.rst +++ b/service_container/lazy_services.rst @@ -25,7 +25,8 @@ until you interact with the proxy in some way. .. caution:: - Lazy services do not support `final`_ classes. + Lazy services do not support `final`_ classes. You can use `Interface + Proxifying`_ to work around this limitation. Installation ------------ @@ -97,6 +98,81 @@ To check if your proxy works you can check the interface of the received object: `ocramius/proxy-manager`_, the container will skip over the ``lazy`` flag and directly instantiate the service as it would normally do. +Interface Proxifying +-------------------- + +Under the hood, proxies generated to lazily load services inherit from the class +used by the service. But sometimes this is not possible at all (`final`_ classes +can not be extended for example) or not convenient. + +To workaround this limitation, you can configure a proxy to only implements +specific interfaces. + +.. versionadded:: 4.2 + + Proxyfying interfaces was introduced in Symfony 4.2. + +.. configuration-block:: + + .. code-block:: yaml + + # config/services.yaml + services: + App\Twig\AppExtension: + lazy: 'Twig\Extension\ExtensionInterface' + # or a complete definition: + lazy: true + tags: + - { name: 'proxy', interface: 'Twig\Extension\ExtensionInterface' } + + .. code-block:: xml + + + + + + + + + + + + + + + .. code-block:: php + + // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + + use App\Twig\AppExtension; + use Twig\Extension\ExtensionInterface; + + return function(ContainerConfigurator $configurator) { + $services = $configurator->services(); + + $services->set(AppExtension::class) + ->lazy() + ->tag('proxy', ['interface' => ExtensionInterface::class]) + ; + }; + +The virtual `proxy`_ injected into other services will only implement the +specified interfaces and will not extend the original service class allowing to +lazy load service using `final`_ classes. You can configure the proxy to +implement multiple interfaces by repeating the "proxy" tag. + +.. tip:: + + This features can also act as a "safe guard". Because the proxy does not + extends the original class, only the methods defined by the interfaces can + be called, preventing to call implementation specific one. It also prevents + injecting the dependency at all if you type hinted a concrete implementation + instead of the interface. + Additional Resources --------------------