diff --git a/packages/container/src/GenericContainer.php b/packages/container/src/GenericContainer.php index 02d8bdae8..12e2538cc 100644 --- a/packages/container/src/GenericContainer.php +++ b/packages/container/src/GenericContainer.php @@ -28,6 +28,9 @@ final class GenericContainer implements Container { use HasInstance; + /** @var array, DynamicInitializer> */ + private array $resolvedDynamicInitializers = []; + public function __construct( /** @var ArrayIterator $definitions */ private(set) ArrayIterator $definitions = new ArrayIterator(), @@ -81,6 +84,7 @@ public function setInitializers(array $initializers): self public function setDynamicInitializers(array $dynamicInitializers): self { $this->dynamicInitializers = new ArrayIterator($dynamicInitializers); + $this->resolvedDynamicInitializers = []; return $this; } @@ -330,6 +334,7 @@ public function removeInitializer(ClassReflector|string $initializerClass): Cont ); unset($this->dynamicInitializers[$index]); + unset($this->resolvedDynamicInitializers[$initializerClass->getName()]); return $this; } @@ -444,8 +449,11 @@ private function initializerForClass(ClassReflector $target, null|string|UnitEnu // Loop through the registered initializers to see if // we have something to handle this class. foreach ($this->dynamicInitializers as $initializerClass) { - /** @var DynamicInitializer $initializer */ - $initializer = $this->resolve($initializerClass); + if (! isset($this->resolvedDynamicInitializers[$initializerClass])) { + $this->resolvedDynamicInitializers[$initializerClass] = $this->resolve($initializerClass); + } + + $initializer = $this->resolvedDynamicInitializers[$initializerClass]; if (! $initializer->canInitialize(class: $target, tag: $tag)) { continue; @@ -719,6 +727,7 @@ public function addResettable(string|ClassReflector $resettableClass): Container public function reset(): self { $this->resolvedSingletons = new ArrayIterator(); + $this->resolvedDynamicInitializers = []; foreach ($this->resettables as $resettableClass) { /** @var Resettable $resettable */ diff --git a/packages/container/tests/ContainerTest.php b/packages/container/tests/ContainerTest.php index a3e22824b..9a66cc8c2 100644 --- a/packages/container/tests/ContainerTest.php +++ b/packages/container/tests/ContainerTest.php @@ -34,6 +34,7 @@ use Tempest\Container\Tests\Fixtures\ContainerObjectDInitializer; use Tempest\Container\Tests\Fixtures\ContainerObjectE; use Tempest\Container\Tests\Fixtures\ContainerObjectEInitializer; +use Tempest\Container\Tests\Fixtures\CountingDynamicInitializer; use Tempest\Container\Tests\Fixtures\DecoratedClass; use Tempest\Container\Tests\Fixtures\DecoratedInterface; use Tempest\Container\Tests\Fixtures\DecoratorClass; @@ -157,6 +158,19 @@ public function test_call_tries_to_transform_unmatched_values(): void $this->assertSame('other', $return->id); } + public function test_dynamic_initializer_instances_are_reused(): void + { + CountingDynamicInitializer::reset(); + + $container = new GenericContainer(); + $container->addInitializer(CountingDynamicInitializer::class); + + $container->get(ContainerObjectA::class); + $container->get(ContainerObjectA::class); + + $this->assertSame(1, CountingDynamicInitializer::$instances); + } + public function test_arrays_are_automatically_created(): void { $container = new GenericContainer(); diff --git a/packages/container/tests/Fixtures/CountingDynamicInitializer.php b/packages/container/tests/Fixtures/CountingDynamicInitializer.php new file mode 100644 index 000000000..938683ff0 --- /dev/null +++ b/packages/container/tests/Fixtures/CountingDynamicInitializer.php @@ -0,0 +1,37 @@ +counted) { + $this->counted = true; + self::$instances++; + } + + return false; + } + + public function initialize(ClassReflector $class, null|string|UnitEnum $tag, Container $container): object + { + throw new \LogicException('CountingDynamicInitializer should not initialize objects.'); + } +}