diff --git a/packages/debug/src/Debug.php b/packages/debug/src/Debug.php index 9ba9757931..cd17c4ef24 100644 --- a/packages/debug/src/Debug.php +++ b/packages/debug/src/Debug.php @@ -40,8 +40,10 @@ public static function resolve(): self */ public function log(array $items, bool $writeToLog = true, bool $writeToOut = true): void { + static $isDispatchingItemsDebuggedEvent = false; + $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); - $callPath = $trace[1]['file'] . ':' . $trace[1]['line']; + $callPath = ($trace[1]['file'] ?? 'unknown') . ':' . ($trace[1]['line'] ?? 0); if ($writeToLog) { $this->writeToLog($items, $callPath); @@ -51,7 +53,17 @@ public function log(array $items, bool $writeToLog = true, bool $writeToOut = tr $this->writeToOut($items, $callPath); } - $this->eventBus?->dispatch(new ItemsDebugged($items)); + if (! $this->eventBus || $isDispatchingItemsDebuggedEvent) { + return; + } + + $isDispatchingItemsDebuggedEvent = true; + + try { + $this->eventBus->dispatch(new ItemsDebugged($items)); + } finally { + $isDispatchingItemsDebuggedEvent = false; + } } private function writeToLog(array $items, string $callPath): void diff --git a/tests/Integration/Debug/DebugTest.php b/tests/Integration/Debug/DebugTest.php index b01e089e78..d366dc80b2 100644 --- a/tests/Integration/Debug/DebugTest.php +++ b/tests/Integration/Debug/DebugTest.php @@ -4,6 +4,7 @@ namespace Tests\Tempest\Integration\Debug; +use PHPUnit\Framework\Attributes\Test; use stdClass; use Tempest\Debug\Debug; use Tempest\Debug\ItemsDebugged; @@ -26,4 +27,21 @@ public function test_event(): void Debug::resolve()->log(['foo', $class], writeToLog: false, writeToOut: false); } + + #[Test] + public function recursive_debug_inside_event_listener_does_not_cause_infinite_loop(): void + { + $dispatchCount = 0; + + $eventBus = $this->container->get(EventBus::class); + $eventBus->listen(function (ItemsDebugged $event) use (&$dispatchCount): void { + $dispatchCount++; + + Debug::resolve()->log(['recursive call'], writeToLog: false, writeToOut: false); + }); + + Debug::resolve()->log(['initial call'], writeToLog: false, writeToOut: false); + + $this->assertSame(1, $dispatchCount); + } }