diff --git a/src/DependencyInjector.php b/src/DependencyInjector.php index e2dc61c..485920b 100644 --- a/src/DependencyInjector.php +++ b/src/DependencyInjector.php @@ -23,12 +23,21 @@ class DependencyInjector // Post Resolver Callbacks protected array $_postResolver = []; - protected ?ReflectionObserver $_reflectionObserver = null; + /** + * @var ReflectionObserver[] + */ + protected array $_reflectionObservers = []; + + public function addReflectionObserver(ReflectionObserver $observer): ReflectionObserver + { + $this->_reflectionObservers[] = $observer; + return $observer; + } public function setReflectionObserver(ReflectionObserver $observer): ReflectionObserver { - $this->_reflectionObserver = $observer; - return $this->_reflectionObserver; + $this->_reflectionObservers = [$observer]; + return $observer; } public function factory($abstract, string|callable $generator, $mode = self::MODE_MUTABLE) @@ -247,11 +256,16 @@ protected function _resolveParameters(\ReflectionMethod $reflection, array $para public function resolveMethod(object $object, ?string $method, ...$parameters): mixed { $reflection = new \ReflectionMethod($object, $method); - $this->_reflectionObserver?->observe($reflection); - if($this->_reflectionObserver instanceof ReflectionInterrupt && $this->_reflectionObserver->shouldInterruptMethod()) + + foreach ($this->_reflectionObservers as $observer) { - return $this->_reflectionObserver->interruptMethod(); + $observer->observe($reflection); + if($observer instanceof ReflectionInterrupt && $observer->shouldInterruptMethod()) + { + return $observer->interruptMethod(); + } } + return $this->_postResolve($reflection->invokeArgs($object, $this->_resolveParameters($reflection, $parameters))); } @@ -266,7 +280,12 @@ public function resolveMethod(object $object, ?string $method, ...$parameters): public function resolveObject(string $className, ...$parameters): object { $reflection = new \ReflectionClass($className); - $this->_reflectionObserver?->observe($reflection); + + foreach ($this->_reflectionObservers as $observer) + { + $observer->observe($reflection); + } + $constructor = $reflection->getConstructor(); if($constructor) { diff --git a/tests/DependencyInjectorTest.php b/tests/DependencyInjectorTest.php index 73ea6f1..74a7c00 100644 --- a/tests/DependencyInjectorTest.php +++ b/tests/DependencyInjectorTest.php @@ -11,6 +11,7 @@ use Packaged\Tests\DiContainer\Supporting\MethodCaller; use Packaged\Tests\DiContainer\Supporting\NeedyObject; use Packaged\Tests\DiContainer\Supporting\ResolvableObject; +use Packaged\Tests\DiContainer\Supporting\SecondObserver; use Packaged\Tests\DiContainer\Supporting\ServiceInterface; use Packaged\Tests\DiContainer\Supporting\ServiceOne; use Packaged\Tests\DiContainer\Supporting\ServiceTwo; @@ -344,4 +345,23 @@ public function testWatchResolveAttributes() static::assertInstanceOf(AttributeWatcherTest::class, $wt2); static::assertCount(3, $attributes->attributes()); } + + public function testWatchWithMultipleObservers() + { + $di = new DependencyInjector(); + + // Resolve still functions without a watcher + $wt = $di->resolve(AttributeWatcherTest::class); + static::assertInstanceOf(AttributeWatcherTest::class, $wt); + + // With resolver + $attributes = new AttributeWatcher(); + $another = new SecondObserver(); + $di->addReflectionObserver($attributes); + $di->addReflectionObserver($another); + $wt2 = $di->resolve(AttributeWatcherTest::class); + static::assertInstanceOf(AttributeWatcherTest::class, $wt2); + static::assertCount(3, $attributes->attributes()); + static::assertCount(2, $another->attributes()); + } } diff --git a/tests/Supporting/SecondObserver.php b/tests/Supporting/SecondObserver.php new file mode 100644 index 0000000..6424f75 --- /dev/null +++ b/tests/Supporting/SecondObserver.php @@ -0,0 +1,31 @@ +_attributes; + } + + public function observe($reflection): void + { + if($reflection instanceof \ReflectionClass || $reflection instanceof \ReflectionMethod) + { + $attributes = $reflection->getAttributes(); + + foreach($attributes as $attribute) + { + if ($attribute->getName() != 'Packaged\Tests\DiContainer\abc') + { + $this->_attributes[] = $attribute; + } + } + } + } +}