Исключения
Программа не всегда может выполнить то, о чём её просят: файл не найден, данные некорректны, деление на ноль. Исключения — это способ сообщить о такой ситуации и обработать её в подходящем месте.
throw и try/catch
Оператор throw «бросает» исключение: выполнение функции прерывается. Поймать его можно блоком catch, а код, в котором оно может возникнуть, помещают в try:
<?php
function divide(int $a, int $b): float
{
if ($b === 0) {
throw new InvalidArgumentException('Делить на ноль нельзя');
}
return $a / $b;
}
try {
echo divide(10, 2), "\n";
echo divide(1, 0);
} catch (InvalidArgumentException $e) {
echo 'Ошибка: ', $e->getMessage();
}Первый вызов сработал, второй бросил исключение, и управление сразу перешло в catch. Метод getMessage() возвращает текст, переданный при создании исключения.
Что будет без catch
Если исключение никто не поймал, программа останавливается с сообщением Fatal error: Uncaught .... Поэтому исключение должно быть обработано хотя бы на самом верхнем уровне программы.
finally
Блок finally выполняется всегда — и после успешного try, и после catch. В нём освобождают ресурсы: закрывают файлы и соединения.
<?php
try {
echo "Открываем файл\n";
throw new RuntimeException('Сбой чтения');
} catch (RuntimeException $e) {
echo $e->getMessage(), "\n";
} finally {
echo 'Закрываем файл';
}Свои исключения
Исключение — это объект класса, поэтому можно создавать свои, наследуя Exception. Отдельный класс позволяет ловить именно эту ошибку и не путать её с другими:
<?php
class NotEnoughMoney extends Exception {}
function pay(int $balance, int $price): int
{
if ($price > $balance) {
throw new NotEnoughMoney('Не хватает ' . ($price - $balance));
}
return $balance - $price;
}
try {
pay(100, 250);
} catch (NotEnoughMoney $e) {
echo $e->getMessage(); // Не хватает 150
}Встроенные ошибки
PHP сам бросает исключения при некоторых ошибках — например, при целочисленном делении на ноль или передаче значения неподходящего типа:
<?php
try {
echo intdiv(1, 0);
} catch (DivisionByZeroError $e) {
echo $e->getMessage(); // Division by zero
}Ошибки языка наследуются от Error, а обычные исключения — от Exception. Общий для них тип — Throwable.
Частая ошибка
Пустой блок catch «проглатывает» ошибку: программа продолжает работать с неверными данными, а найти причину потом очень трудно. Ловите только те исключения, которые умеете обработать, и никогда не оставляйте catch пустым.