getTraceAsString()
Метод PHP getTraceAsString(): как он возвращает стек вызовов исключения в виде строки, как читать вывод и как его логировать или отображать.
Что делает getTraceAsString()
getTraceAsString() — метод, доступный для каждого PHP-исключения (любого класса, реализующего Throwable — Exception, Error и их подклассов). Он возвращает стек вызовов — цепочку функций и методов, активных в момент выброса исключения — в виде единой читаемой строки.
Стек вызовов отвечает на вопрос «как выполнение добралось сюда?» Когда что-то выбрасывается глубоко внутри кода, одно лишь сообщение (getMessage()) говорит вам что пошло не так, а трассировка показывает точный путь вызовов, который к этому привёл. Именно поэтому она является наиболее ценным инструментом при отладке ошибки, которую сложно воспроизвести.
getTraceAsString() — строковая версия getTrace(), возвращающей те же данные в виде структурированного массива. Используйте getTrace(), когда нужно программно анализировать отдельные кадры; используйте getTraceAsString(), когда требуется просто записать или вывести трассировку.
Синтаксис
public Throwable::getTraceAsString(): stringМетод не принимает аргументов и объявлен final в базовых классах Exception и Error, поэтому всегда возвращает стандартный формат трассировки PHP. Вызывается на объекте пойманного исключения внутри блока catch:
<?php
try {
// Code that may throw an exception
} catch (Throwable $e) {
$trace = $e->getTraceAsString();
}Перехват Throwable (а не только Exception) позволяет также обрабатывать объекты Error, такие как TypeError и DivisionByZeroError. Полную иерархию см. в главе Exception.
Полный запускаемый пример
Следующий скрипт выбрасывает исключение на два уровня вглубь, чтобы наглядно показать, как выглядит строка трассировки:
<?php
function loadUser(int $id): array
{
throw new InvalidArgumentException("No user with id $id");
}
function handleRequest(): void
{
loadUser(42);
}
try {
handleRequest();
} catch (Throwable $e) {
echo $e->getTraceAsString();
}Вывод:
#0 /app/index.php(10): loadUser(42)
#1 /app/index.php(14): handleRequest()
#2 {main}Чтение вывода
Каждая строка — это один кадр в стеке вызовов, перечисленный начиная с самого внутреннего:
#0,#1, … — номер кадра.#0— вызов, выполнявшийся в момент выброса исключения; более высокие номера — вызывающие функции выше по стеку./app/index.php(10)— файл и номер строки места вызова.loadUser(42)— вызванная функция или метод с аргументами. Длинные строковые аргументы обрезаются (например,'/etc/app/missin...') для сохранения читаемости трассировки.#2 {main}— специальный последний кадр, обозначающий скрипт верхнего уровня (глобальную область видимости).
Место выброса (точный файл и строка, где был выполнен throw) не включается в эту строку — оно хранится в getFile() и getLine().
Примеры
Пример 1: Запись трассировки в файл
В продакшене вы редко хотите показывать трассировку пользователю — вы записываете её для последующего анализа. Объедините сообщение, файл и строку с трассировкой для получения полной записи:
<?php
try {
// Code that may throw an exception
} catch (Throwable $e) {
$entry = sprintf(
"[%s] %s in %s:%d\n%s\n\n",
date('Y-m-d H:i:s'),
$e->getMessage(),
$e->getFile(),
$e->getLine(),
$e->getTraceAsString()
);
file_put_contents('/path/to/app.log', $entry, FILE_APPEND | LOCK_EX);
}LOCK_EX предотвращает перемешивание записей в журнале при одновременных запросах. Для реальных приложений предпочтительнее библиотека логирования, такая как Monolog, однако базовые данные — та же строка, что вы получаете здесь.
Пример 2: Отображение трассировки в браузере (только для разработки)
При локальной разработке бывает удобно вывести трассировку прямо на страницу. Оберните её в <pre>, чтобы сохранить переносы строк, и экранируйте, чтобы содержимое трассировки не могло внедрить HTML:
<?php
try {
// Code that may throw an exception
} catch (Throwable $e) {
echo '<pre>' . htmlspecialchars($e->getTraceAsString()) . '</pre>';
}Никогда не показывайте трассировки конечным пользователям в продакшене — они раскрывают пути к файлам, структуру кода и иногда значения аргументов, которые могут помочь злоумышленникам. Защитите это проверкой среды окружения.
Пример 3: Сохранение трассировки при повторном выбросе
Когда вы перехватываете низкоуровневое исключение и выбрасываете более информативное, передайте оригинальное как предыдущее исключение, чтобы его трассировка не была потеряна:
<?php
try {
// some database call that throws PDOException
} catch (PDOException $e) {
throw new RuntimeException('Could not load the report', 0, $e);
}Новое RuntimeException имеет собственную трассировку, а getPrevious() возвращает оригинальное исключение (и его getTraceAsString()). Стандартный обработчик непойманных исключений в PHP выводит оба, в цепочке.
Распространённые ловушки
- Трассировка описывает место выброса, а не место перехвата. Она фиксируется в момент создания исключения, поэтому вызов
getTraceAsString()позже всё равно показывает, где возникло исключение, а не где вы его обработали. - Аргументы могут быть усечены или скрыты. Длинные строки сокращаются; при включённой настройке INI
zend.exception_ignore_args(по умолчанию в многих продакшн-конфигурациях) значения аргументов полностью опускаются из соображений безопасности. - Метод возвращает строку, а не
null. Даже для исключения, выброшенного на верхнем уровне, вы получите как минимум кадр#0 {main}.
Связанные методы
getTrace()— те же данные в виде структурированного массива.getMessage()— читаемое сообщение об ошибке.getCode()— числовой код исключения.getPrevious()— связанное предыдущее исключение.set-exception-handler()— глобальная обработка непойманных исключений.
Заключение
getTraceAsString() преобразует стек вызовов исключения в компактную, пригодную для логирования строку, что делает его одним из наиболее ценных инструментов диагностики ошибок в PHP. Используйте его вместе с getMessage(), getFile() и getLine() для полной картины каждого сбоя, записывайте в лог вместо отображения пользователям в продакшене и сохраняйте цепочку с помощью getPrevious() при повторном выбросе.