getPrevious()
Функция PHP getPrevious() возвращает предыдущее исключение, переданное в конструктор текущего.
Введение
Exception::getPrevious() возвращает исключение, переданное в качестве третьего аргумента конструктору исключения PHP — то исключение, которое стало причиной текущего. Метод определён в базовом классе Exception (и Error), поэтому все типы исключений PHP его наследуют.
На этой странице рассматривается, что возвращает getPrevious(), как строить цепочку «обёрнутых» исключений, как обходить такую цепочку и каких распространённых ошибок следует избегать.
Синтаксис и возвращаемое значение
final public Throwable::getPrevious(): ?Throwable- Параметры: отсутствуют.
- Возвращает: предыдущий
Throwable(исключениеExceptionилиError), если он был задан, иначеnull. - Метод объявлен как
final, поэтому переопределить его в собственных подклассах исключений невозможно.
«Предыдущее» исключение задаётся при создании исключения с третьим аргументом:
throw new RuntimeException("High-level failure", 0, $originalException);
// message ^code ^previousБазовый пример
При повторном бросании исключения передавайте оригинальное в качестве третьего аргумента конструктора, чтобы не потерять контекст:
<?php
try {
try {
throw new Exception("Inner error");
} catch (Exception $inner) {
// Wrap the low-level error in a more meaningful one,
// keeping the original as "previous".
throw new Exception("Outer error", 0, $inner);
}
} catch (Exception $e) {
echo "Caught: " . $e->getMessage() . "\n";
$previous = $e->getPrevious();
if ($previous !== null) {
echo "Caused by: " . $previous->getMessage() . "\n";
}
}
?>Вывод:
Caught: Outer error
Caused by: Inner errorgetPrevious() возвращает объект $inner, переданный при создании, поэтому можно читать его сообщение, код или трассировку стека точно так же, как у любого другого исключения.
Зачем оборачивать исключения
Распространённый шаблон — перехватить низкоуровневое техническое исключение (ошибка запроса к базе данных, отсутствующий файл) и перебросить более высокоуровневое, предметное — не теряя при этом исходную причину:
<?php
function loadUser(int $id): array
{
try {
// Pretend this talks to a database and fails.
throw new RuntimeException("SQLSTATE[HY000]: connection refused");
} catch (RuntimeException $dbError) {
// Callers care about "could not load user", not SQL internals,
// but we keep the SQL error available via getPrevious().
throw new RuntimeException("Unable to load user #$id", 0, $dbError);
}
}
try {
loadUser(42);
} catch (RuntimeException $e) {
echo $e->getMessage() . "\n";
echo "Root cause: " . $e->getPrevious()->getMessage() . "\n";
}
?>Вывод:
Unable to load user #42
Root cause: SQLSTATE[HY000]: connection refusedЭто позволяет поддерживать чистые высокоуровневые сообщения об ошибках, сохраняя при этом технические подробности для логирования и отладки.
Обход всей цепочки исключений
Предыдущее исключение само может иметь предыдущее. Чтобы исследовать всю цепочку, организуйте цикл, пока getPrevious() возвращает значение, отличное от null:
<?php
$a = new Exception("Level 1: low-level cause");
$b = new Exception("Level 2: mid-level wrapper", 0, $a);
$c = new Exception("Level 3: top-level error", 0, $b);
$current = $c;
while ($current !== null) {
echo $current->getMessage() . "\n";
$current = $current->getPrevious();
}
?>Вывод:
Level 3: top-level error
Level 2: mid-level wrapper
Level 1: low-level causeРаспространённые ошибки
- При отсутствии предыдущего исключения возвращается
null. Если исключение создано без третьего аргумента,getPrevious()возвращаетnull. Всегда проверяйте условие!== null(или используйте цикл) перед вызовом методов на результате. - Третий аргумент конструктора — предыдущее исключение, а не код. Сигнатура:
new Exception($message, $code, $previous). Распространённая ошибка — передать предыдущее исключение во второй слот, где PHP ожидает целочисленный код. - Метод доступен только для чтения. Метода
setPrevious()не существует. Цепочка фиксируется в момент создания, поэтому причину нужно передавать при создании оборачивающего исключения. var_dump($e)уже показывает цепочку. Когда необработанное исключение приводится к строке (или PHP выводит его сам), трассировка «Caused by» / предыдущего исключения включается автоматически —getPrevious()нужен тогда, когда требуется исследовать цепочку в коде.
Связанные методы
getPrevious() — один из нескольких методов инспекции, которые предоставляет каждое исключение PHP:
getMessage()— читаемое человеком сообщение об ошибке.getCode()— числовой код ошибки.getTrace()— трассировка стека в виде array.getTraceAsString()— трассировка стека в виде string.
Более широкий контекст о try/catch и пользовательских классах исключений см. в разделе Исключения PHP.
Итоги
getPrevious() возвращает исключение, ставшее причиной текущего, что позволяет строить цепочки исключений: перехватить низкоуровневую ошибку, бросить содержательное высокоуровневое исключение и при этом сохранить исходную причину для отладки. При отсутствии предыдущего исключения метод возвращает null, поэтому перед использованием результата обязательно проверяйте это условие или организуйте цикл.