From 839f00c147db609135e2556151a41d59da207826 Mon Sep 17 00:00:00 2001 From: David Matejka Date: Sat, 7 May 2016 18:52:55 +0200 Subject: [PATCH] ContainerBuilder::getClassList: optimized performance [Closes #108] --- src/DI/ContainerBuilder.php | 18 ++++++++++++++---- src/DI/ServiceDefinition.php | 18 ++++++++++++++++++ 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/DI/ContainerBuilder.php b/src/DI/ContainerBuilder.php index 34ae594cc..41fc2c328 100644 --- a/src/DI/ContainerBuilder.php +++ b/src/DI/ContainerBuilder.php @@ -39,6 +39,9 @@ class ContainerBuilder /** @var array for auto-wiring */ private $classList = FALSE; + /** @var bool */ + private $classListNeedsRefresh = TRUE; + /** @var string[] of classes excluded from auto-wiring */ private $excludedClasses = []; @@ -59,6 +62,7 @@ class ContainerBuilder */ public function addDefinition($name, ServiceDefinition $definition = NULL) { + $this->classListNeedsRefresh = TRUE; if (!is_string($name) || !$name) { // builder is not ready for falsy names such as '0' throw new Nette\InvalidArgumentException(sprintf('Service name must be a non-empty string, %s given.', gettype($name))); } @@ -66,7 +70,13 @@ public function addDefinition($name, ServiceDefinition $definition = NULL) if (isset($this->definitions[$name])) { throw new Nette\InvalidStateException("Service '$name' has already been added."); } - return $this->definitions[$name] = $definition ?: new ServiceDefinition; + if (!$definition) { + $definition = new ServiceDefinition; + } + $definition->setNotifier(function () { + $this->classListNeedsRefresh = TRUE; + }); + return $this->definitions[$name] = $definition; } @@ -77,6 +87,7 @@ public function addDefinition($name, ServiceDefinition $definition = NULL) */ public function removeDefinition($name) { + $this->classListNeedsRefresh = TRUE; $name = isset($this->aliases[$name]) ? $this->aliases[$name] : $name; unset($this->definitions[$name]); } @@ -258,10 +269,9 @@ public function findByTag($tag) private function getClassList() { - static $prev; - if ($this->classList !== FALSE && $prev !== serialize($this->definitions)) { + if ($this->classList !== FALSE && $this->classListNeedsRefresh) { $this->prepareClassList(); - $prev = serialize($this->definitions); + $this->classListNeedsRefresh = FALSE; } return $this->classList ?: []; } diff --git a/src/DI/ServiceDefinition.php b/src/DI/ServiceDefinition.php index 30226ff94..6f48556c6 100644 --- a/src/DI/ServiceDefinition.php +++ b/src/DI/ServiceDefinition.php @@ -48,12 +48,16 @@ class ServiceDefinition /** @var string|NULL create | get */ private $implementType; + /** @var callable */ + private $notifier = 'pi'; // = noop + /** * @return self */ public function setClass($class, array $args = []) { + call_user_func($this->notifier); $this->class = $class ? ltrim($class, '\\') : NULL; if ($args) { $this->setFactory($class, $args); @@ -76,6 +80,7 @@ public function getClass() */ public function setFactory($factory, array $args = []) { + call_user_func($this->notifier); $this->factory = $factory instanceof Statement ? $factory : new Statement($factory, $args); return $this; } @@ -210,6 +215,7 @@ public function getTag($tag) */ public function setAutowired($state = TRUE) { + call_user_func($this->notifier); $this->autowired = (bool) $state; return $this; } @@ -250,6 +256,7 @@ public function isDynamic() */ public function setImplement($interface) { + call_user_func($this->notifier); $this->implement = ltrim($interface, '\\'); return $this; } @@ -303,10 +310,21 @@ public function getInject() } + /** + * @internal + */ + public function setNotifier(callable $notifier) + { + $this->notifier = $notifier; + return $this; + } + + public function __clone() { $this->factory = unserialize(serialize($this->factory)); $this->setup = unserialize(serialize($this->setup)); + $this->notifier = NULL; } }