From 3fbced6c10c1a2bc6c185c4a0ba0da085cc2ce70 Mon Sep 17 00:00:00 2001 From: Rias Date: Sat, 19 Jul 2025 11:40:55 +0200 Subject: [PATCH 1/3] Add Singleton and Scoped attributes --- .../Container/Attributes/Scoped.php | 10 ++++++ .../Container/Attributes/Singleton.php | 10 ++++++ src/Illuminate/Container/Container.php | 32 +++++++++++++++-- tests/Container/ContainerTest.php | 36 +++++++++++++++++++ 4 files changed, 85 insertions(+), 3 deletions(-) create mode 100644 src/Illuminate/Container/Attributes/Scoped.php create mode 100644 src/Illuminate/Container/Attributes/Singleton.php diff --git a/src/Illuminate/Container/Attributes/Scoped.php b/src/Illuminate/Container/Attributes/Scoped.php new file mode 100644 index 000000000000..1cf04e08d4b8 --- /dev/null +++ b/src/Illuminate/Container/Attributes/Scoped.php @@ -0,0 +1,10 @@ +instances[$abstract]) || - (isset($this->bindings[$abstract]['shared']) && - $this->bindings[$abstract]['shared'] === true); + if (isset($this->instances[$abstract])) { + return true; + } + + if (isset($this->bindings[$abstract]['shared']) && $this->bindings[$abstract]['shared'] === true) { + return true; + } + + if (! class_exists($abstract)) { + return false; + } + + $reflection = new ReflectionClass($abstract); + + if (! empty($reflection->getAttributes(Singleton::class))) { + return true; + } + + if (! empty($reflection->getAttributes(Scoped::class))) { + if (! in_array($abstract, $this->scopedInstances, true)) { + $this->scopedInstances[] = $abstract; + } + + return true; + } + + return false; } /** diff --git a/tests/Container/ContainerTest.php b/tests/Container/ContainerTest.php index 0302729bc970..6f2ac5d26ed8 100755 --- a/tests/Container/ContainerTest.php +++ b/tests/Container/ContainerTest.php @@ -3,6 +3,8 @@ namespace Illuminate\Tests\Container; use Attribute; +use Illuminate\Container\Attributes\Scoped; +use Illuminate\Container\Attributes\Singleton; use Illuminate\Container\Container; use Illuminate\Container\EntryNotFoundException; use Illuminate\Contracts\Container\BindingResolutionException; @@ -740,6 +742,30 @@ public function testMethodLevelContextualBinding() $this->assertInstanceOf(ContainerImplementationStub::class, $result); } + public function testContainerSingletonAttribute() + { + $container = new Container; + $firstInstantiation = $container->get(ContainerSingletonAttribute::class); + + $secondInstantiation = $container->get(ContainerSingletonAttribute::class); + + $this->assertSame($firstInstantiation, $secondInstantiation); + } + + public function testContainerScopedAttribute() + { + $container = new Container; + $firstInstantiation = $container->get(ContainerScopedAttribute::class); + $secondInstantiation = $container->get(ContainerScopedAttribute::class); + + $this->assertSame($firstInstantiation, $secondInstantiation); + + $container->forgetScopedInstances(); + + $thirdInstantiation = $container->get(ContainerScopedAttribute::class); + $this->assertNotSame($firstInstantiation, $thirdInstantiation); + } + // public function testContainerCanCatchCircularDependency() // { // $this->expectException(\Illuminate\Contracts\Container\CircularDependencyException::class); @@ -899,3 +925,13 @@ public function __construct( $this->currentlyResolving = $currentlyResolving; } } + +#[Singleton] +class ContainerSingletonAttribute +{ +} + +#[Scoped] +class ContainerScopedAttribute +{ +} From a28c9ae0be3249c4b4b314b15230f7c820325ee1 Mon Sep 17 00:00:00 2001 From: Rias Date: Sat, 19 Jul 2025 12:07:36 +0200 Subject: [PATCH 2/3] Add to instances on subsequent calls so reflection isn't necessary after --- src/Illuminate/Container/Container.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Illuminate/Container/Container.php b/src/Illuminate/Container/Container.php index 1074f0f90f96..25511c348300 100755 --- a/src/Illuminate/Container/Container.php +++ b/src/Illuminate/Container/Container.php @@ -269,6 +269,10 @@ public function isShared($abstract) $reflection = new ReflectionClass($abstract); if (! empty($reflection->getAttributes(Singleton::class))) { + if (! in_array($abstract, $this->instances, true)) { + $this->instances[] = $abstract; + } + return true; } From cf5803bb000df19e2753275b11bd5f41def8b17c Mon Sep 17 00:00:00 2001 From: Rias Date: Sat, 19 Jul 2025 21:44:03 +0200 Subject: [PATCH 3/3] Don't add it to the instances --- src/Illuminate/Container/Container.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Illuminate/Container/Container.php b/src/Illuminate/Container/Container.php index 25511c348300..1074f0f90f96 100755 --- a/src/Illuminate/Container/Container.php +++ b/src/Illuminate/Container/Container.php @@ -269,10 +269,6 @@ public function isShared($abstract) $reflection = new ReflectionClass($abstract); if (! empty($reflection->getAttributes(Singleton::class))) { - if (! in_array($abstract, $this->instances, true)) { - $this->instances[] = $abstract; - } - return true; }