From 1e641d657832bb5fe437f578a795039272eb2cd7 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Mon, 25 Nov 2024 11:38:08 +0100 Subject: [PATCH] creating lazy services in PHP 8.4 WIP --- src/DI/Container.php | 7 ++++++- src/DI/Extensions/DIExtension.php | 28 ++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/DI/Container.php b/src/DI/Container.php index d72639a63..c4aa29bbe 100644 --- a/src/DI/Container.php +++ b/src/DI/Container.php @@ -32,6 +32,9 @@ class Container /** @var array[] type => (high, low, no) => services */ protected array $wiring = []; + /** @var string[] service name => class */ + protected array $lazy = []; + /** @var object[] service name => instance */ private array $instances = []; @@ -215,7 +218,9 @@ public function createService(string $name): object if ($callback = ($this->factories[$name] ?? null)) { $service = $this->preventDeadLock($name, fn() => $callback()); } elseif (isset($this->methods[$method])) { - $service = $this->preventDeadLock($name, fn() => $this->$method()); + $service = isset($this->lazy[$name]) + ? (new \ReflectionClass($this->lazy[$name]))->newLazyProxy($this->$method(...)) + : $this->preventDeadLock($name, fn() => $this->$method()); } else { throw new MissingServiceException(sprintf("Service '%s' not found.", $name)); } diff --git a/src/DI/Extensions/DIExtension.php b/src/DI/Extensions/DIExtension.php index 5b789cffa..7775aff9b 100644 --- a/src/DI/Extensions/DIExtension.php +++ b/src/DI/Extensions/DIExtension.php @@ -10,6 +10,8 @@ namespace Nette\DI\Extensions; use Nette; +use Nette\DI\Definitions\ServiceDefinition; +use Nette\PhpGenerator as Php; use Tracy; @@ -36,6 +38,7 @@ public function __construct(bool $debugMode = false) public array $excluded = []; public ?string $parentClass = null; public object $export; + public bool $lazy = false; }; $this->config->export = new class { public bool $parameters = true; @@ -62,6 +65,7 @@ public function afterCompile(Nette\PhpGenerator\ClassType $class): void $class->setExtends($this->config->parentClass); } + $this->initializeLazy($class); $this->restrictParameters($class); $this->restrictTags($class); $this->restrictTypes($class); @@ -75,6 +79,30 @@ public function afterCompile(Nette\PhpGenerator\ClassType $class): void } + private function initializeLazy(Nette\PhpGenerator\ClassType $class): void + { + if (!$this->config->lazy || PHP_VERSION_ID < 80400) { + return; + } + + $classes = []; + foreach ($this->getContainerBuilder()->getDefinitions() as $name => $def) { + if ($def instanceof ServiceDefinition + && is_string($def->getEntity()) + && ($rc = new \ReflectionClass($def->getEntity())) + && !$rc->isInternal() + ) { + $classes[$name] = $rc->getName(); + } + } + + (new Php\ClassManipulator($class)) + ->inheritProperty('lazy') + ->setComment(null) + ->setValue($classes); + } + + private function restrictParameters(Nette\PhpGenerator\ClassType $class): void { if (!$this->config->export->parameters) {