Bring the lazy load service feature on-demand to dependencies injections.
This module is a proof of concept (see below the history).
I hope this will be improved enough to be added in core.
How to load a service lazily ?
If the injected dependency is declared from a *.services.yml file, prefix the service name by lazy.
Initial service yml declaration :
services:
lazy_service_example.event_subscriber:
class: Drupal\lazy_service_example\EventSubscriber\LazyServiceSubscriber
arguments: [ '@lazy_service_example.mylazy' ]
tags:
- { name: event_subscriber }
Renamed service declaration :
services:
lazy_service_example.event_subscriber:
class: Drupal\lazy_service_example\EventSubscriber\LazyServiceSubscriber
arguments: [ '@lazy.lazy_service_example.mylazy' ]
tags:
- { name: event_subscriber }
In a create() method :
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('lazy_service_example.mylazy')
);
}
Renamed service :
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('lazy.lazy_service_example.mylazy')
);
}
Why this module ?
This module comes from two reflections :
- I needed to inject (again) a service into an existing service (class or whatever), since my method needed this one. But other methods in the service not needed it. I thought again it was sad to load some services we will not use in some cases. It's against the idea of loading only what we need. But nothing allow to do this. I keep my sad feeling and move on one more time.
- Few days later, during SymfonyCon Disneyland Paris 2022, i attended the great presentation of Nicolas Grekas "Unleashing the power of lazy objects in PHP" (see his article https://nicolas-grekas.medium.com/revisiting-lazy-loading-proxies-in-php...), where he talks among other things about adding an annotation on services to be able to lazy load injected services, and so only load them when they really are required.
Amazing, it's like he had heard me few days ago.
But service lazy loading already exists in Drupal!
Right, we can already lazy load services declaring lazy: true to a service, except we have to know when we create a service that we need it as a lazy service. And if you add a service as lazy, you still need to launch manually a script to generate proxyClass, a file which will be generated in the module the service belong to. Who know when the service you define in core or contrib module will be needed as lazy by another module ?
For example, in a controller, i have 2 methods : pageArticles() and front(). I need a myLazy service in pageArticles, but not in front. myLazy service has been loaded thanks to Dependency injection, but it's defined by another module and i should not define it as lazy service since it comes from another module (remember, right know, the lazy service needs to define a service as lazy AND generate manually a ProxyClass).
How lazy_service module works and how it plans to solve this.
If you want to load a service lazily, instead of declaring your service name in dependency injection, prefix it's label by 'lazy.', so calling a service 'my_module.my_lazy', call it 'lazy.my_module.my_lazy'
Module extends ServiceProviderBase and alter container builder to :
- Generate the proxy class automatically
- Replace lazy definitions by the proxyclass service
Currently, the script from core generate proxyclass in the module where the service is defined. This script has to main issues :
- File is generated with the class name. In case you have 2 services to generate with 2 differents namespaces in the same module, only one file will be kept.
- In case you wish to alter the service definitions to make a service from another module lazy, calling the script will add the file in the module the service belongs to, but the next time you will update this module, the file will be removed.
To fix this, i think the generated proxyclass has to be place in a proxy class directory, like we make it from caches for example, a directory where we can generate files on demand.
The only directory which fit for it in Drupal is files directory.
So proxyClass from lazy_service are created in sites/default/files/ProxyClass, and will keep the namespace directory to avoid two files with same name to override each others. Example of directory for Messenger service : sites/default/Files/ProxyClass/Drupal/Core/Messenger
Feel free to open discussion on issues (or participate on existing if subject is already opened)
Project information
- Project categories: Developer tools, Performance
- Created by goz on , updated
Stable releases for this project are covered by the security advisory policy.
There are currently no supported stable releases.
Releases
Development version: 1.0.x-dev updated 23 Jul 2024 at 13:37 UTC
