Создание пользовательских исключений
Расширяйте класс Exception, чтобы создавать типы ошибок для конкретной предметной области
«Создание пользовательских исключений» — бесплатный урок PHP Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения PHP Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс PHP Academy содержит 4 уроков всего.
Зачем нужны собственные исключения?
Собственные исключения позволяют:
- Отличать ошибки приложения от общих ошибок PHP
- Хранить данные, относящиеся к предметной области (идентификатор заказа, идентификатор пользователя и т. д.)
- Перехватывать конкретные типы ошибок на разных уровнях
- Создавать понятную и самодокументируемую иерархию ошибок
Расширение Exception
Создайте собственное исключение, расширив базовый класс Exception:
<?php
class ValidationException extends \Exception
{
private array $errors;
public function __construct(array $errors, string $message = '', int $code = 0)
{
$this->errors = $errors;
parent::__construct($message ?: implode(', ', $errors), $code);
}
public function getErrors(): array
{
return $this->errors;
}
}Использование собственного исключения
Выбрасывайте и перехватывайте собственное исключение:
<?php
function createUser(array $data): void {
$errors = [];
if (empty($data['email'])) $errors[] = 'Email required';
if (empty($data['name'])) $errors[] = 'Name required';
if ($errors) {
throw new ValidationException($errors);
}
// save user...
}
try {
createUser([]);
} catch (ValidationException $e) {
foreach ($e->getErrors() as $err) {
echo '- ' . $err . PHP_EOL;
}
}Проектирование иерархии исключений
Спроектируйте иерархию для своей предметной области:
<?php
// Base exception for your app
class AppException extends \RuntimeException {}
// Domain-specific exceptions
class NotFoundException extends AppException {}
class AuthException extends AppException {}
class PaymentException extends AppException {}
// Specific payment errors
class InsufficientFundsException extends PaymentException {
public function __construct(public readonly float $balance, public readonly float $required) {
parent::__construct("Insufficient funds: have $balance, need $required");
}
}Перехват по иерархии
Перехватывайте базовый класс, чтобы обрабатывать все производные исключения:
<?php
try {
processPayment($order);
} catch (InsufficientFundsException $e) {
echo 'Low balance: need ' . $e->required;
} catch (PaymentException $e) {
echo 'Payment failed: ' . $e->getMessage();
} catch (AppException $e) {
echo 'App error: ' . $e->getMessage();
} catch (\Throwable $e) {
// Last resort
error_log($e);
}Добавление контекста к исключениям
Дополняйте исключения дополнительными данными для отладки:
<?php
class HttpException extends \RuntimeException
{
public function __construct(
private int $statusCode,
string $message = '',
?\Throwable $previous = null
) {
parent::__construct($message, $statusCode, $previous);
}
public function getStatusCode(): int
{
return $this->statusCode;
}
}Пример HTTP-исключения
Использование HTTP-исключения в веб-приложении:
<?php
try {
$user = findUserById($id);
if (!$user) throw new HttpException(404, 'User not found');
if (!$user->canAccess($resource)) {
throw new HttpException(403, 'Access denied');
}
} catch (HttpException $e) {
http_response_code($e->getStatusCode());
echo json_encode(['error' => $e->getMessage()]);
}Исключения на основе интерфейсов
Используйте интерфейсы, чтобы объединять несвязанные классы исключений:
<?php
interface UserFacingException
{
public function getUserMessage(): string;
}
class ValidationException extends \Exception implements UserFacingException
{
public function getUserMessage(): string
{
return 'Please check your input: ' . $this->getMessage();
}
}
// In controller:
catch (UserFacingException $e) {
echo $e->getUserMessage();
}Шаблон именованного конструктора
Используйте статические фабричные методы для распространённых сценариев исключений:
<?php
class OrderException extends \RuntimeException
{
public static function notFound(int $id): self
{
return new self("Order #$id not found", 404);
}
public static function alreadyShipped(int $id): self
{
return new self("Order #$id already shipped", 409);
}
}
throw OrderException::notFound($orderId);Сериализация исключений
Преобразуйте данные исключения в массив для журналирования или ответов API:
<?php
function exceptionToArray(\Throwable $e): array {
return [
'type' => get_class($e),
'message' => $e->getMessage(),
'code' => $e->getCode(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'trace' => $e->getTraceAsString(),
'previous' => $e->getPrevious()
? exceptionToArray($e->getPrevious())
: null,
];
}Лучшие практики для собственных исключений
Рекомендации по проектированию собственных исключений:
- Расширяйте
RuntimeExceptionдля неожиданных ситуаций - Расширяйте
LogicExceptionдля ошибок программиста (недопустимых аргументов) - Не создавайте класс исключения для каждого возможного сообщения — вместо этого используйте коды
- Имена классов исключений должны быть в PascalCase и заканчиваться на Exception
- Документируйте, какие исключения может выбрасывать каждый метод
Быстрая проверка
Какой базовый класс PHP следует расширить, чтобы создать собственное исключение, представляющее логическую ошибку в коде?
Итоги: собственные исключения
Кратко о собственных исключениях:
- Расширяйте
Exceptionили его подкласс - Добавляйте свойства и методы, относящиеся к предметной области
- Проектируйте иерархии — перехватывайте родительский класс, чтобы перехватить все дочерние
- Используйте интерфейсы для объединения несвязанных исключений
- Используйте статические именованные конструкторы для ясности
- Всегда вызывайте
parent::__construct()
Часто задаваемые вопросы
Урок «Создание пользовательских исключений» бесплатный?
Да — полный текст урока «Создание пользовательских исключений» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс PHP Academy, подпишись на CoddyKit PRO. Курс PHP Academy содержит 4 уроков всего.
Чему я научусь в уроке «Создание пользовательских исключений»?
Расширяйте класс Exception, чтобы создавать типы ошибок для конкретной предметной области Ты практикуешь PHP Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать PHP Academy?
Предыдущий опыт не требуется. PHP Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.
Сколько времени занимает урок «Создание пользовательских исключений»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке PHP Academy?
Да. Каждый урок PHP Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Типы ошибок PHP и их отчётность
- Try, Catch и Finally
- Создание пользовательских исключений
- Журналирование ошибок и лучшие практики