From 45628c97e9372edc370c2f776eb12d5a146593b7 Mon Sep 17 00:00:00 2001 From: Steffan Date: Sun, 8 Nov 2026 11:38:10 +0100 Subject: [PATCH] fix(container): use registration keys for cycle tracking --- packages/container/src/GenericContainer.php | 4 +-- packages/container/tests/ContainerTest.php | 40 +++++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/packages/container/src/GenericContainer.php b/packages/container/src/GenericContainer.php index 8901e4900b..dfa443a0ed 100644 --- a/packages/container/src/GenericContainer.php +++ b/packages/container/src/GenericContainer.php @@ -393,7 +393,7 @@ private function resolveDependency(string $className, string|UnitEnum|null $tag // Check if the class has been registered as a singleton. if ($singletonDefinition = $this->singletonDefinitions[$dependencyName] ?? null) { - $this->resolveChain()->add($class); + $this->resolveChain()->add($dependencyName); try { $instance = $singletonDefinition instanceof Closure ? $singletonDefinition($this) : $singletonDefinition; @@ -408,7 +408,7 @@ private function resolveDependency(string $className, string|UnitEnum|null $tag // Check if a callable has been registered to resolve this class. if ($definition = $this->definitions[$dependencyName] ?? null) { - $this->resolveChain()->add(new FunctionReflector($definition)); + $this->resolveChain()->add($dependencyName); try { return $definition($this); diff --git a/packages/container/tests/ContainerTest.php b/packages/container/tests/ContainerTest.php index b37f7e8e6b..e1b9881e69 100644 --- a/packages/container/tests/ContainerTest.php +++ b/packages/container/tests/ContainerTest.php @@ -311,6 +311,46 @@ public function tagged_singleton(): void $this->assertSame('cli', $container->get(TaggedDependency::class, 'cli')->name); } + #[Test] + public function tagged_singleton_can_depend_on_unresolved_default_singleton(): void + { + $container = new GenericContainer(); + $container->singleton(TaggedDependency::class, fn () => new TaggedDependency('default')); + $container->singleton( + TaggedDependency::class, + fn (GenericContainer $container) => clone $container->get(TaggedDependency::class), + tag: 'copy', + ); + + $tagged = $container->get(TaggedDependency::class, tag: 'copy'); + $default = $container->get(TaggedDependency::class); + + $this->assertSame('default', $tagged->name); + $this->assertNotSame($default, $tagged); + $this->assertSame($default, $container->get(TaggedDependency::class)); + $this->assertSame($tagged, $container->get(TaggedDependency::class, tag: 'copy')); + } + + #[Test] + public function registered_factories_can_share_a_source_location(): void + { + $wrap = fn (callable $factory) => fn (GenericContainer $container) => $factory($container); + + $container = new GenericContainer(); + $container->register( + ContainerObjectB::class, + $wrap(fn (GenericContainer $container) => new ContainerObjectB($container->get(ContainerObjectA::class))), + ); + $container->register(ContainerObjectA::class, $wrap(fn () => new ContainerObjectA())); + + $first = $container->get(ContainerObjectB::class); + $second = $container->get(ContainerObjectB::class); + + $this->assertInstanceOf(ContainerObjectA::class, $first->a); + $this->assertNotSame($first, $second); + $this->assertNotSame($first->a, $second->a); + } + #[Test] public function tagged_singleton_with_enum(): void {