From 65a498a07df10c8f6e41eb819c373ed5c5ca821c Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Fri, 6 Feb 2026 15:30:07 +0300 Subject: [PATCH 1/5] Fix missing items in stack trace HTML output when handling a PHP error --- CHANGELOG.md | 1 + src/Renderer/HtmlRenderer.php | 4 ---- tests/Renderer/HtmlRendererTest.php | 18 +++++++++++++++++ tests/Support/TestHelper.php | 30 +++++++++++++++++++++++++++++ 4 files changed, 49 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7059bc6..2f05922 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - Chg #162: Replace deprecated `ThrowableResponseFactory` class usage to new one, and remove it (@vjik) - Enh #163: Explicitly import classes, functions, and constants in "use" section (@mspirkov) +- Bug #164: Fix missing items in stack trace HTML output when handling a PHP error (@vjik) ## 4.3.2 January 09, 2026 diff --git a/src/Renderer/HtmlRenderer.php b/src/Renderer/HtmlRenderer.php index d9074d8..a3c8eb6 100644 --- a/src/Renderer/HtmlRenderer.php +++ b/src/Renderer/HtmlRenderer.php @@ -321,10 +321,6 @@ public function renderCallStack(Throwable $t, array $trace = []): string ); $index = 1; - if ($t instanceof ErrorException) { - $index = 0; - } - foreach ($trace as $traceItem) { $file = !empty($traceItem['file']) ? $traceItem['file'] : null; $line = !empty($traceItem['line']) ? $traceItem['line'] : null; diff --git a/tests/Renderer/HtmlRendererTest.php b/tests/Renderer/HtmlRendererTest.php index 2304231..8010d67 100644 --- a/tests/Renderer/HtmlRendererTest.php +++ b/tests/Renderer/HtmlRendererTest.php @@ -16,6 +16,8 @@ use Yiisoft\ErrorHandler\Exception\ErrorException; use Yiisoft\ErrorHandler\Renderer\HtmlRenderer; +use Yiisoft\ErrorHandler\Tests\Support\TestHelper; + use function dirname; use function file_exists; use function file_put_contents; @@ -160,6 +162,22 @@ static function (int $code, string $message) use (&$errorMessage) { $this->assertSame('file(not-exist): Failed to open stream: No such file or directory', $errorMessage); } + public function testRenderCallStackWithErrorException(): void + { + $renderer = new HtmlRenderer(); + + $result = $renderer->renderCallStack( + new ErrorException('test-message'), + TestHelper::generateTrace([true, true, false, true]) + ); + + $this->assertStringContainsString('1. ', $result); + $this->assertStringContainsString('2. ', $result); + $this->assertStringContainsString('3. ', $result); + $this->assertStringContainsString('4. ', $result); + $this->assertStringContainsString('5. ', $result); + } + public function testRenderRequest(): void { $renderer = new HtmlRenderer(); diff --git a/tests/Support/TestHelper.php b/tests/Support/TestHelper.php index db285ef..af081aa 100644 --- a/tests/Support/TestHelper.php +++ b/tests/Support/TestHelper.php @@ -9,6 +9,8 @@ use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\UriInterface; +use function dirname; + final class TestHelper { public static function createRequest( @@ -30,4 +32,32 @@ public static function getResponseContent(ResponseInterface $response): string $body->rewind(); return $body->getContents(); } + + /** + * Generates a trace array in the format identical to `debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS)`. + * + * @param bool[] $isVendor List of boolean values where `true` means a vendor file and `false` means an application file. + * + * @return array + */ + public static function generateTrace(array $isVendor): array + { + $rootPath = dirname(__DIR__, 2); + $vendorFile = $rootPath . '/vendor/autoload.php'; + $appFile = $rootPath . '/src/ErrorHandler.php'; + + $trace = []; + + foreach ($isVendor as $index => $vendor) { + $trace[] = [ + 'file' => $vendor ? $vendorFile : $appFile, + 'line' => $index + 1, + 'function' => 'testFunction' . $index, + 'class' => 'TestClass', + 'type' => '->', + ]; + } + + return $trace; + } } From 344ccc5e8bc8c1960d8354419f3e99aebbc7017a Mon Sep 17 00:00:00 2001 From: vjik <525501+vjik@users.noreply.github.com> Date: Fri, 6 Feb 2026 12:31:14 +0000 Subject: [PATCH 2/5] Apply PHP CS Fixer and Rector changes (CI) --- tests/Renderer/HtmlRendererTest.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/Renderer/HtmlRendererTest.php b/tests/Renderer/HtmlRendererTest.php index 8010d67..3d464f0 100644 --- a/tests/Renderer/HtmlRendererTest.php +++ b/tests/Renderer/HtmlRendererTest.php @@ -15,7 +15,6 @@ use RuntimeException; use Yiisoft\ErrorHandler\Exception\ErrorException; use Yiisoft\ErrorHandler\Renderer\HtmlRenderer; - use Yiisoft\ErrorHandler\Tests\Support\TestHelper; use function dirname; @@ -168,7 +167,7 @@ public function testRenderCallStackWithErrorException(): void $result = $renderer->renderCallStack( new ErrorException('test-message'), - TestHelper::generateTrace([true, true, false, true]) + TestHelper::generateTrace([true, true, false, true]), ); $this->assertStringContainsString('1. ', $result); From 0ae92e14bc56fec5ba4746045c1b020bf9f17133 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Fri, 6 Feb 2026 17:16:24 +0300 Subject: [PATCH 3/5] fix --- src/ErrorHandler.php | 1 + tests/ErrorHandlerTest.php | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ErrorHandler.php b/src/ErrorHandler.php index e78b68c..f78097c 100644 --- a/src/ErrorHandler.php +++ b/src/ErrorHandler.php @@ -141,6 +141,7 @@ public function register(): void unset($backtrace[0]['function'], $backtrace[0]['class'], $backtrace[0]['type'], $backtrace[0]['args']); } else { array_shift($backtrace); + array_shift($backtrace); } throw new ErrorException($message, $severity, $severity, $file, $line, null, $backtrace); diff --git a/tests/ErrorHandlerTest.php b/tests/ErrorHandlerTest.php index 0d1ec79..c63afb5 100644 --- a/tests/ErrorHandlerTest.php +++ b/tests/ErrorHandlerTest.php @@ -138,8 +138,8 @@ public function testHandleTriggerErrorWithCatching(): void $backtrace = $exception->getBacktrace(); $this->assertNotEmpty($backtrace); - $this->assertArrayHasKey('file', $backtrace[0]); - $this->assertSame(__FILE__, $backtrace[0]['file']); + $this->assertArrayHasKey('class', $backtrace[0]); + $this->assertSame(self::class, $backtrace[0]['class']); $this->errorHandler->unregister(); } From 49ea294d1f0395c3da5fefe32fc9e1aa19a54d2b Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Fri, 6 Feb 2026 17:27:50 +0300 Subject: [PATCH 4/5] fix --- src/ErrorHandler.php | 6 ++---- tests/ErrorHandlerTest.php | 5 +++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/ErrorHandler.php b/src/ErrorHandler.php index f78097c..00dc35a 100644 --- a/src/ErrorHandler.php +++ b/src/ErrorHandler.php @@ -137,12 +137,10 @@ public function register(): void } $backtrace = debug_backtrace(0); - if (isset($backtrace[0]['file'])) { - unset($backtrace[0]['function'], $backtrace[0]['class'], $backtrace[0]['type'], $backtrace[0]['args']); - } else { - array_shift($backtrace); + if (!isset($backtrace[0]['file'])) { array_shift($backtrace); } + array_shift($backtrace); throw new ErrorException($message, $severity, $severity, $file, $line, null, $backtrace); }); diff --git a/tests/ErrorHandlerTest.php b/tests/ErrorHandlerTest.php index c63afb5..fefd38c 100644 --- a/tests/ErrorHandlerTest.php +++ b/tests/ErrorHandlerTest.php @@ -4,6 +4,7 @@ namespace Yiisoft\ErrorHandler\Tests; +use mysql_xdevapi\BaseResult; use PHPUnit\Framework\Attributes\WithoutErrorHandler; use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; @@ -114,8 +115,8 @@ public function testHandleErrorWithCatching(): void $backtrace = $exception->getBacktrace(); $this->assertNotEmpty($backtrace); - $this->assertSame(__FILE__, $backtrace[0]['file']); - $this->assertSame(['file', 'line'], array_keys($backtrace[0])); + $this->assertArrayHasKey('class', $backtrace[0]); + $this->assertSame(self::class, $backtrace[0]['class']); $this->errorHandler->unregister(); } From 643d92f53f9fc9a909b3cb371ef8ae0bb92157af Mon Sep 17 00:00:00 2001 From: vjik <525501+vjik@users.noreply.github.com> Date: Fri, 6 Feb 2026 14:28:31 +0000 Subject: [PATCH 5/5] Apply PHP CS Fixer and Rector changes (CI) --- tests/ErrorHandlerTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/ErrorHandlerTest.php b/tests/ErrorHandlerTest.php index fefd38c..eb1772c 100644 --- a/tests/ErrorHandlerTest.php +++ b/tests/ErrorHandlerTest.php @@ -4,7 +4,6 @@ namespace Yiisoft\ErrorHandler\Tests; -use mysql_xdevapi\BaseResult; use PHPUnit\Framework\Attributes\WithoutErrorHandler; use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface;