getTrace()
Узнайте, как Exception::getTrace() возвращает трассировку стека в виде массива, что содержит каждый фрейм и чем он отличается от getTraceAsString().
PHP getTrace()
Exception::getTrace() возвращает трассировку стека исключения в виде массива. Каждый элемент описывает один вызов функции или метода, находившийся в стеке вызовов в момент выброса исключения, упорядоченный от точки выброса наружу. Это один из самых полезных инструментов для выяснения где и как произошла ошибка.
На этой странице рассматривается, что возвращает getTrace(), структура каждого фрейма трассировки и чем он отличается от более привычного getTraceAsString(). Метод определён в базовом интерфейсе Throwable, поэтому он доступен для каждого объекта Exception и Error.
public Exception::getTrace(): arrayМетод не принимает аргументов и возвращает индексированный массив. Фрейм 0 — самый внутренний вызов (функция, которая фактически выбросила исключение), а индексы растут по направлению к внешнему вызывающему коду.
Быстрый пример
Следующий скрипт выбрасывает исключение из вложенного вызова и выводит каждый фрейм трассировки:
<?php
function readConfig($path) {
return parseFile($path);
}
function parseFile($path) {
throw new Exception("Cannot read file: $path");
}
try {
readConfig('/etc/app.conf');
} catch (Exception $e) {
$trace = $e->getTrace();
echo "Number of frames: " . count($trace) . "\n";
foreach ($trace as $i => $frame) {
echo "#$i {$frame['function']}() called in {$frame['file']} on line {$frame['line']}\n";
}
}Вывод:
Number of frames: 2
#0 parseFile() called in /path/to/script.php on line 4
#1 readConfig() called in /path/to/script.php on line 12Обратите внимание: фрейм функции, которая выбросила исключение (parseFile), указывает строку, откуда она была вызвана (строка 4, внутри readConfig), а не строку с оператором throw. Строка выброса доступна отдельно через getLine() и getFile().
Что содержит каждый фрейм трассировки
Каждый фрейм является ассоциативным массивом. Наиболее полезные ключи:
| Ключ | Описание |
|---|---|
function | Имя функции или метода, который был вызван. |
line | Строка в file, откуда был сделан вызов. |
file | Файл, откуда был сделан вызов. |
class | Имя класса (только для вызовов методов). |
type | -> для вызовов экземпляра, :: для статических вызовов. |
args | Массив аргументов, переданных в вызов. |
Следующий скрипт полностью инспектирует один фрейм:
<?php
function divide($a, $b) {
if ($b === 0) {
throw new InvalidArgumentException('Division by zero');
}
return $a / $b;
}
try {
divide(10, 0);
} catch (Exception $e) {
print_r($e->getTrace()[0]);
}Вывод:
Array
(
[file] => /path/to/script.php
[line] => 11
[function] => divide
[args] => Array
(
[0] => 10
[1] => 0
)
)Замечание по безопасности: запись
argsсодержит фактические значения аргументов, которые могут включать пароли, токены или другие конфиденциальные данные. Никогда не передавайте сырой массивgetTrace()конечным пользователям — вместо этого записывайте его на стороне сервера. Параметр INIzend.exception_ignore_argsв PHP (включён по умолчанию начиная с PHP 7.4) удаляетargs, чтобы избежать утечки чувствительных данных; если вы не видите ключargs, именно поэтому.
getTrace() vs getTraceAsString()
getTrace() возвращает сырой массив, который можно форматировать, фильтровать или сериализовать по своему усмотрению. Если вам нужна просто читаемая строка, используйте getTraceAsString(), который возвращает ту же информацию в предварительно отформатированном виде:
<?php
try {
throw new RuntimeException('Something broke');
} catch (Throwable $e) {
echo $e->getTraceAsString();
}Используйте форму массива, когда хотите программно обойти фреймы (например, создать кастомный отчёт об ошибке или отправить структурированные данные в сервис логирования), и форму строки для быстрого вывода или строк лога.
Место getTrace() в API исключений
getTrace() — один из нескольких доступных только для чтения методов-акцессоров каждого исключения. Они наиболее эффективны при совместном использовании внутри блока catch:
getMessage()— читаемое сообщение об ошибке.getCode()— числовой код ошибки.getFile()иgetLine()— место выброса исключения.getTraceAsString()— трассировка в виде строки.getPrevious()— связанное исключение, если таковое имеется.
Для общего понимания выброса и перехвата исключений см. throw, try и класс Exception.
Лучшие практики обработки исключений в PHP
Чтобы ваш код был удобен в сопровождении и лёгок в отладке, важно следовать лучшим практикам при обработке исключений в PHP. Вот несколько советов, которые стоит помнить:
1. Используйте информативные сообщения исключений.
При выбрасывании исключения убедитесь, что сообщение информативно и полезно. Оно должно объяснять, что пошло не так и как это исправить. Например:
<?php
if ($someCondition) {
throw new Exception('Invalid input: the email address is not valid.');
}2. Перехватывайте только те исключения, которые можете обработать.
При перехвате исключений важно обрабатывать только те, с которыми вы умеете работать. Если перехватить исключение, которое вы не можете обработать, можно скрыть настоящую проблему и усложнить отладку. Например:
<?php
try {
// Some code that may throw an exception.
} catch (InvalidArgumentException $e) {
// Handle the invalid argument exception.
} catch (Exception $e) {
// Handle all other exceptions.
}3. Логируйте исключения.
Логирование исключений помогает диагностировать проблемы и устранять неполадки. Хорошей практикой является запись исключений в файл или базу данных для последующего анализа. Например:
<?php
try {
// Some code that may throw an exception.
} catch (Exception $e) {
error_log($e->getMessage(), 0);
}4. Используйте иерархии исключений.
Использование иерархий исключений помогает организовать код и упрощает перехват определённых типов исключений. Например, можно создать класс DatabaseException, расширяющий класс Exception, и выбрасывать его при возникновении ошибки базы данных. После этого при обработке ошибок базы данных можно перехватывать только экземпляры DatabaseException.
Заключение
Обработка исключений — критически важный аспект программирования на PHP, а метод getTrace() является ценным инструментом для отладки и диагностики исключений. Возвращая обратную трассировку контекста выполнения, вы можете точно определить, где произошло исключение и как оно было вызвано.
В этом руководстве мы рассмотрели основы обработки исключений в PHP, включая выброс и перехват исключений, а также лучшие практики эффективного использования исключений. Мы также изучили метод getTrace() и то, как он помогает диагностировать и исправлять ошибки в коде.
Следуя этим лучшим практикам и используя метод getTrace(), вы сможете писать PHP-код, который является надёжным, устойчивым и простым в сопровождении. Обработка исключений может казаться незначительной деталью, но она способна существенно повлиять на качество и удобство использования вашего кода.