From 8f89bd7bd69881669487e91a1b282a5f7f92850e Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 10 Feb 2026 13:38:09 +0100 Subject: [PATCH 1/2] fix(debug): prevent infinite recursion --- packages/debug/src/Debug.php | 14 +++++++++++++- tests/Integration/Debug/DebugTest.php | 18 ++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/packages/debug/src/Debug.php b/packages/debug/src/Debug.php index 9ba9757931..186fa97c14 100644 --- a/packages/debug/src/Debug.php +++ b/packages/debug/src/Debug.php @@ -40,6 +40,8 @@ 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']; @@ -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); + } } From 2df3b8bfa934ba65b1cbcd637b12689c68b56cfb Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 10 Feb 2026 17:33:38 +0100 Subject: [PATCH 2/2] fix(debug): handle missing file/line in backtrace --- packages/debug/src/Debug.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/debug/src/Debug.php b/packages/debug/src/Debug.php index 186fa97c14..cd17c4ef24 100644 --- a/packages/debug/src/Debug.php +++ b/packages/debug/src/Debug.php @@ -43,7 +43,7 @@ public function log(array $items, bool $writeToLog = true, bool $writeToOut = tr 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);