diff --git a/packages/container/src/GenericContainer.php b/packages/container/src/GenericContainer.php index 2483f0640..92fdf6d2e 100644 --- a/packages/container/src/GenericContainer.php +++ b/packages/container/src/GenericContainer.php @@ -24,6 +24,15 @@ final class GenericContainer implements Container { use HasInstance; + /** @var array */ + private array $resolved = []; + + /** @var array */ + private static array $classReflectors = []; + + /** @var array */ + private array $initializerCache = []; + public function __construct( /** @var ArrayIterator $definitions */ private(set) ArrayIterator $definitions = new ArrayIterator(), @@ -124,7 +133,7 @@ public function register(string $className, callable $definition): self public function unregister(string $className, bool $tagged = false): self { - unset($this->definitions[$className], $this->singletons[$className]); + unset($this->definitions[$className], $this->singletons[$className], $this->resolved[$className]); if ($tagged) { $singletons = array_filter( @@ -134,6 +143,12 @@ public function unregister(string $className, bool $tagged = false): self ); $this->setSingletons($singletons); + + foreach (array_keys($this->resolved) as $key) { + if (str_starts_with($key, "{$className}#")) { + unset($this->resolved[$key]); + } + } } return $this; @@ -262,7 +277,10 @@ private function invokeFunction(FunctionReflector|Closure $callback, mixed ...$p public function addInitializer(ClassReflector|string $initializerClass): Container { if (! $initializerClass instanceof ClassReflector) { - $initializerClass = new ClassReflector($initializerClass); + if (! isset(self::$classReflectors[$initializerClass])) { + self::$classReflectors[$initializerClass] = new ClassReflector($initializerClass); + } + $initializerClass = self::$classReflectors[$initializerClass]; } // First, we check whether this is a DynamicInitializer, @@ -292,7 +310,10 @@ public function addInitializer(ClassReflector|string $initializerClass): Contain public function removeInitializer(ClassReflector|string $initializerClass): Container { if (! $initializerClass instanceof ClassReflector) { - $initializerClass = new ClassReflector($initializerClass); + if (! isset(self::$classReflectors[$initializerClass])) { + self::$classReflectors[$initializerClass] = new ClassReflector($initializerClass); + } + $initializerClass = self::$classReflectors[$initializerClass]; } if ($initializerClass->getType()->matches(DynamicInitializer::class)) { @@ -323,18 +344,26 @@ public function addDecorator(ClassReflector|string $decoratorClass, ClassReflect private function resolve(string $className, null|string|UnitEnum $tag = null, mixed ...$params): object { + $key = $this->resolveTaggedName($className, $tag); + + if (isset($this->resolved[$key])) { + return $this->resolved[$key]; + } $instance = $this->resolveDependency($className, $tag, ...$params); if ($this->decorators[$className] ?? null) { $instance = $this->resolveDecorator($className, $instance, $tag, ...$params); } - return $instance; + return $this->resolved[$key] = $instance; } private function resolveDependency(string $className, null|string|UnitEnum $tag = null, mixed ...$params): object { - $class = new ClassReflector($className); + if (! isset(self::$classReflectors[$className])) { + self::$classReflectors[$className] = new ClassReflector($className); + } + $class = self::$classReflectors[$className]; $dependencyName = $this->resolveTaggedName($className, $tag); @@ -397,14 +426,21 @@ private function initializerForBuiltin(TypeReflector $target, string $tag): ?Ini private function initializerForClass(ClassReflector $target, null|string|UnitEnum $tag = null): null|Initializer|DynamicInitializer { + $key = $this->resolveTaggedName($target->getName(), $tag); + + if (array_key_exists($key, $this->initializerCache)) { + return $this->initializerCache[$key]; + } + // Initializers themselves can't be initialized, // otherwise you'd end up with infinite loops if ($target->getType()->matches(Initializer::class) || $target->getType()->matches(DynamicInitializer::class)) { - return null; + return $this->initializerCache[$key] = null; } if ($initializerClass = $this->initializers[$this->resolveTaggedName($target->getName(), $tag)] ?? null) { - return $this->resolve($initializerClass); + $initializer = $this->resolve($initializerClass); + return $this->initializerCache[$key] = $initializer; } // Loop through the registered initializers to see if @@ -417,15 +453,18 @@ private function initializerForClass(ClassReflector $target, null|string|UnitEnu continue; } - return $initializer; + return $this->initializerCache[$key] = $initializer; } - return null; + return $this->initializerCache[$key] = null; } private function autowire(string $className, mixed ...$params): object { - $classReflector = new ClassReflector($className); + if (! isset(self::$classReflectors[$className])) { + self::$classReflectors[$className] = new ClassReflector($className); + } + $classReflector = self::$classReflectors[$className]; $constructor = $classReflector->getConstructor(); @@ -645,7 +684,11 @@ private function resolveTaggedName(string $className, null|string|UnitEnum $tag) private function resolveDecorator(string $className, mixed $instance, null|string|UnitEnum $tag = null, mixed ...$params): object { foreach ($this->decorators[$className] ?? [] as $decoratorClass) { - $decoratorClassReflector = new ClassReflector($decoratorClass); + if (! isset(self::$classReflectors[$decoratorClass])) { + self::$classReflectors[$decoratorClass] = new ClassReflector($decoratorClass); + } + $decoratorClassReflector = self::$classReflectors[$decoratorClass]; + $constructor = $decoratorClassReflector->getConstructor(); $parameters = $constructor?->getParameters();