Quantcast
Channel: Issues for Drupal core
Viewing all articles
Browse latest Browse all 302528

DIC: Lazy instantiation of service dependencies (ProxyManager for "proxy services")

$
0
0

Problem/Motivation

Currently, if a service A depends on another service B, then B needs to be instantiated at the same time or before the instantiation of A.
This happens even if A might never actually use B during the script lifetime.

The alternative is to have A depend on the container instead of B, so A can get B from the container at the time it is needed, and not before.
The downside: This makes A less predictable, because it now has access to *all the stuff in the container*, not just B.

One example is the cron service ... its loaded on every request,
as it is a dependency on system.automatic_cron, but the actual logic is nearly never needed.

Proposed resolution

For simple services (not using a factory) introduce a flag: lazy: true

Once this flag is set, there will be an automatic wrapper written into the dumped container. This wrapper wraps every public method,
initializes the unterlying service, and calls its methods.

Remaining tasks

User interface changes

API changes

Original report by @donquixote

Suggested solution:
A "LazyService" wrapper, that gives A access to exactly one service from the container, but not more.
The wrapper itself has access to the container, but it will only ever use it for one specific key.

I am going to upload an implementation with some added magic.
The idea is that
- the wrapper can be used in place of the real service.
- the first operation on the wrapper will trigger instantiation of the real service.
- the reference to the wrapper will be replaced with the real service, once instantiated.
- any further operations can happen directly on the real service, without any indirection overhead.
- nothing (except the wrapper) has a reference to the container.

Usage:

<?php
    $builder
= new LazyService(Drupal::getContainer(), 'breadcrumb');
   
// This will tell the wrapper to replace $builder with the real service, once instantiated.
   
$builder->bindReference($builder);
   
assert('Drupal\Component\Container\LazyService'=== get_class($builder));
   
// This will trigger the lazy instantiation via magic __call().
   
$breadcrumb = $builder->build(...);
   
assert('Drupal\Core\Breadcrumb\BreadcrumbManager'=== get_class($builder));
   
// Additional calls happen directly on the service, without indirection.
   
$breadcrumb2 = $builder->build(...);
?>

Related:
#1863816: Allow plugins to have services injected


Viewing all articles
Browse latest Browse all 302528

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>