获取堆栈跟踪
当报告异常或代码中错误行为的错误时,提供一个或多个堆栈跟踪至关重要。为了理解原因,您首先必须了解什么是堆栈跟踪,以及它如何对您作为开发人员以及库维护人员有用。
堆栈跟踪的结构
堆栈跟踪之所以如此称呼,是因为它允许人们查看自程序开始以来导致代码中某一点的函数调用轨迹。该点不一定是异常。例如,您可以使用原生 PHP 函数 debug_print_backtrace()
来获取此类跟踪。对于跟踪中的每一行,您都会获得一个文件和一个函数或方法调用,以及该调用的行号。这通常对于理解程序的流程以及程序如何最终出现在意外的位置(例如抛出异常的代码行)非常有帮助。
堆栈跟踪和异常
在 PHP 中,每个异常都带有自己的堆栈跟踪,如果异常未被捕获,则默认显示该堆栈跟踪。当使用 Symfony 时,此类异常会通过自定义异常处理程序,该处理程序会以各种方式增强它们,然后在根据当前的服务器 API(CLI 或非 CLI)显示它们。这意味着,当您不需要程序继续运行时,获取堆栈跟踪的更好方法是抛出异常,如下所示:throw new \Exception();
嵌套异常
当应用程序变得更大时,复杂性通常通过需要保持分离的架构层来解决。例如,如果您有一个 Web 应用程序,该应用程序调用远程 API,则最好使用在您的域中具有特殊含义的异常来包装在进行该调用时抛出的异常,并从中构建适当的 HTTP 异常。可以通过使用 Exception
类的签名中出现的 $previous
参数来嵌套异常:public __construct ([ string $message = "" [, int $code = 0 [, Throwable $previous = NULL ]]] )
这意味着有时,当您从应用程序收到异常时,您实际上可能会收到多个异常。
在堆栈跟踪中查找什么
当使用库时,您将调用您没有编写的代码。当使用框架时,情况正好相反:因为您遵循框架的约定,框架会找到您的代码并调用它,并在事先为您做一些事情,例如路由或访问控制。Symfony 既是一个框架,也是组件库,它会调用您的代码,然后您的代码可能会调用它。这意味着当使用 Symfony 时,您的堆栈跟踪中始终至少有 2 部分,通常是 3 部分:一部分从框架的入口点之一(大多数情况下是 bin/console
或 public/index.php
)开始,并在到达您的代码时结束,大多数时候是在 src
下找到的命令或控制器中。然后,异常要么在您的代码中抛出,要么在您调用的库中抛出。如果是后者,则堆栈跟踪中应该有第三部分,其中包含在 vendor
下的文件中进行的调用。在进入该目录之前,代码会经过无数次的审查过程和 CI 管道,这意味着它成为问题的根源的可能性应该低于来自您的应用程序的代码,因此重要的是您首先关注以 src
开头的行,并查找任何可疑或意外的内容,例如不应该发生的方法调用。
接下来,您可以查看涉及哪些包。vendor
下的文件由 Composer 以以下方式组织:vendor/acme/router
,其中 acme
是供应商,router
是库,acme/router
是 Composer 包。如果您计划报告错误,请确保将其报告给抛出异常的库。composer home acme/router
应该会引导您到正确的位置。由于 Symfony 是一个单体仓库,因此在报告任何组件的错误时,请使用 composer home symfony/symfony
。
使用 Symfony 获取堆栈跟踪
现在我们已经牢记了所有这些,让我们看看如何使用 Symfony 获取堆栈跟踪。
在 Web 浏览器中获取堆栈跟踪
当通过 Web 浏览器从您的开发环境中选择堆栈跟踪时,需要注意以下几件事
- 是否有多个异常?如果是,最有趣的通常是异常 1/n,它在默认异常页面中最后显示(在下面的示例中,它被标记为
exception [1/2]
)。 - 在“堆栈跟踪”选项卡下,您将找到纯文本格式的异常,以便您可以轻松地在错误报告等中共享它们。在执行此操作之前,请务必删除任何敏感信息。
- 您可能会注意到也有一个日志选项卡;此选项卡与堆栈跟踪无关,它仅包含在应用程序的任意位置生成的日志。它们可能与您遇到的异常相关,也可能不相关,但不是术语“堆栈跟踪”所指的内容。

由于堆栈跟踪可能包含敏感数据,因此不应在生产环境中公开它们。虽然更复杂,但仍然可以使用一些解决方案从您的生产环境中获取堆栈跟踪,这些解决方案包括但不限于使用 Monolog 将它们发送到电子邮件地址。
在 CLI 中获取堆栈跟踪
当运行 Symfony 命令时,可能会发生异常。默认情况下,仅显示消息,因为它通常足以理解发生了什么
1 2 3 4 5 6 7 8 9 10 11 12 13 14
$ php bin/console debug:exception
Command "debug:exception" is not defined.
Did you mean one of these?
debug:autowiring
debug:config
debug:container
debug:event-dispatcher
debug:form
debug:router
debug:translation
debug:twig
如果不是这种情况,您可以通过使用 --verbose
增加详细级别来获得堆栈跟踪
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
$ php bin/console --verbose debug:exception
In Application.php line 644:
[Symfony\Component\Console\Exception\CommandNotFoundException]
Command "debug:exception" is not defined.
Did you mean one of these?
debug:autowiring
debug:config
debug:container
debug:event-dispatcher
debug:form
debug:router
debug:translation
debug:twig
Exception trace:
at /app/vendor/symfony/console/Application.php:644
Symfony\Component\Console\Application->find() at /app/vendor/symfony/framework-bundle/Console/Application.php:116
Symfony\Bundle\FrameworkBundle\Console\Application->find() at /app/vendor/symfony/console/Application.php:228
Symfony\Component\Console\Application->doRun() at /app/vendor/symfony/framework-bundle/Console/Application.php:82
Symfony\Bundle\FrameworkBundle\Console\Application->doRun() at /app/vendor/symfony/console/Application.php:140
Symfony\Component\Console\Application->run() at /app/bin/console:42
堆栈跟踪和 API 调用
当从 API 获取异常时,您可能不会获得堆栈跟踪,或者它可能以不适合共享的方式显示。幸运的是,在开发环境中,您可以使用分析器获得纯文本堆栈跟踪。要查找配置文件,您可以查看 X-Debug-Token-Link
响应标头
1 2 3 4 5 6
$ curl --head http://127.0.0.1:8000/api/posts/1
… more headers
X-Debug-Token: 110e1e
X-Debug-Token-Link: http://127.0.0.1:8000/_profiler/110e1e
X-Robots-Tag: noindex
X-Previous-Debug-Token: 209101
点击该链接将引导您到一个与上面在 Web 浏览器中获取堆栈跟踪中描述的页面非常相似的页面。