Исключения и обработка ошибок в PHP
Исключения в PHP: try/catch/finally, бросок через throw, создание своих классов исключений, SPL-исключения.
Исключение (exception) — это объект, который сигнализирует об ошибке во время выполнения программы. Механизм try/catch позволяет перехватить исключение и обработать его, не прерывая работу всего приложения.
Базовый синтаксис try/catch
Код, который может вызвать ошибку, помещают в блок try. Если ошибка возникнет — управление перейдёт в catch:
<?php
function divide(float $a, float $b): float {
if ($b === 0.0) {
throw new \InvalidArgumentException("Деление на ноль недопустимо");
}
return $a / $b;
}
try {
echo divide(10, 2) . "\n"; // OK
echo divide(5, 0); // бросает исключение
} catch (\InvalidArgumentException $e) {
echo "Ошибка: " . $e->getMessage();
}
Вывод:
5 Ошибка: Деление на ноль недопустимо
Метод getMessage() возвращает текст ошибки. Также полезны getCode() и getFile()/getLine() для отладки.
Несколько catch и finally
Можно перехватывать разные типы исключений отдельными блоками. Блок finally выполняется всегда — независимо от того, было ли исключение:
<?php
function processInput(mixed $input): int {
if (!is_numeric($input)) {
throw new \TypeError("Ожидается число, получено: " . gettype($input));
}
if ($input < 0) {
throw new \RangeException("Число должно быть неотрицательным");
}
return (int) $input;
}
try {
echo processInput("abc");
} catch (\TypeError $e) {
echo "Тип некорректен: " . $e->getMessage() . "\n";
} catch (\RangeException $e) {
echo "Диапазон некорректен: " . $e->getMessage() . "\n";
} finally {
echo "Обработка завершена (выполняется всегда)\n";
}
Вывод:
Тип некорректен: Ожидается число, получено: string Обработка завершена (выполняется всегда)
Свои классы исключений
Создавайте собственные классы исключений для разных ситуаций — это упрощает обработку ошибок в большом приложении:
<?php
class UserNotFoundException extends \RuntimeException {}
class UserBannedException extends \RuntimeException {
public function __construct(string $username, int $code = 0) {
parent::__construct("Пользователь «$username» заблокирован", $code);
}
}
function findUser(string $username): array {
$users = ["anna" => ["active" => true], "banned" => ["active" => false]];
if (!isset($users[$username])) {
throw new UserNotFoundException("Пользователь «$username» не найден");
}
if (!$users[$username]["active"]) {
throw new UserBannedException($username);
}
return $users[$username];
}
foreach (["anna", "bob", "banned"] as $name) {
try {
$user = findUser($name);
echo "$name: доступ разрешён\n";
} catch (UserNotFoundException $e) {
echo $e->getMessage() . "\n";
} catch (UserBannedException $e) {
echo $e->getMessage() . "\n";
}
}
Вывод:
anna: доступ разрешён Пользователь «bob» не найден Пользователь «banned» заблокирован
Встроенные SPL-исключения
| Класс | Когда использовать |
|---|---|
\InvalidArgumentException | некорректный аргумент функции |
\RuntimeException | ошибка во время выполнения |
\LogicException | логическая ошибка программы |
\RangeException | значение вне допустимого диапазона |
\TypeError | несовпадение типов |
\OverflowException | переполнение структуры данных |
Не используйте голый
catch (\Exception $e)для всего подряд — так вы скроете настоящую причину ошибки. Перехватывайте конкретные типы исключений.
Коротко
throw new Exception("...")— бросает исключение.try/catch— перехватывает исключение;finally— выполняется всегда.- Разные типы исключений перехватывают отдельными блоками
catch. - Создавайте собственные классы исключений, расширяя
\RuntimeExceptionили\LogicException. - PHP предоставляет богатую иерархию SPL-исключений — используйте их вместо голого
\Exception.