Problem/Motivation
As discussed in #3228623: DX: Creating lazy services is too difficult/obscure/bespoke/brittle the DX for our current lazy service proxies is poor. We tried using symfony lazy services in #3396928: Deprecate Drupal ProxyBuilder in favor of Symfony lazy services however that was not possible due to:
Sadly SF uses eval for the proxy classes which at least I can't see working with our serialized container solution
However we can now use service closures to lazy-load services which are supported by our serialized container.
Steps to reproduce
Proposed resolution
Replacy services tagged 'lazy' with service closures.
Prefer using autowiring and the #[AutowireServiceClosure]
attribute over the !service_closure
yaml command where possible.
https://symfony.com/doc/current/service_container/autowiring.html#genera...
This requires changing the constructor signature and adding a new method to invoke the closure like so:
Before:
public function __construct(
protected CronInterface $cron,
) {}
Service definition:
services:
my_service:
class: Foo\Bar
arguments: ['@cron']
After:
public function __construct(
protected \Closure $cronClosure,
) {}
protected function getCron(): CronInterface {
return ($this->cronClosure)();
}
Service definition:
services:
my_service:
class: Foo\Bar
arguments: [!service_closure '@cron']
Autowiring approach
Before:
public function __construct(
protected CronInterface $cron,
) {}
Service definition:
services:
my_service:
class: Foo\Bar
autowire: true
After:
public function __construct(
#[AutowireServiceClosure('cron')]
protected \Closure $cronClosure,
) {}
protected function getCron(): CronInterface {
return ($this->cronClosure)();
}
Service definition:
services:
my_service:
class: Foo\Bar
autowire: true
Remaining tasks
Current proxies under core/lib/Drupal/Core/ProxyClass
:
├── Batch
│ └── BatchStorage.php
├── Config
│ └── ConfigInstaller.php
├── Cron.php
├── Extension
│ └── ModuleInstaller.php
├── File
│ └── MimeType
│ ├── ExtensionMimeTypeGuesser.php
│ └── MimeTypeGuesser.php
├── Lock
│ ├── DatabaseLockBackend.php
│ └── PersistentDatabaseLockBackend.php
├── Menu
│ └── MenuActiveTrail.php
├── PageCache
│ └── ChainResponsePolicy.php
├── ParamConverter
│ ├── AdminPathConfigEntityConverter.php
│ └── MenuLinkPluginConverter.php
├── Render
│ └── BareHtmlPageRenderer.php
└── Routing
├── MatcherDumper.php
└── RouteBuilder.php
Proxies in core modules:
core/modules/language/src/ProxyClass/LanguageConverter.php
core/modules/node/src/ProxyClass/ParamConverter/NodePreviewConverter.php
core/modules/views_ui/src/ProxyClass/ParamConverter/ViewUIConverter.php