Как обрабатывать ошибки в современном PHP?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Современные подходы к обработке ошибок в PHP
В современном PHP обработка ошибок эволюционировала от простых директив error_reporting к сложной системе исключений и специализированным библиотекам. Вот ключевые аспекты:
1. Исключения (Exceptions) как основа
Основной механизм — использование исключений через try-catch-finally блоки:
try {
$processor = new PaymentProcessor();
$result = $processor->charge($amount);
if ($result->isFailed()) {
throw new PaymentFailedException('Payment processing failed', $result->getCode());
}
return $result;
} catch (PaymentFailedException $e) {
// Специфичная обработка ошибок платежа
$logger->error('Payment failed', ['exception' => $e]);
throw new UserFriendlyException('Unable to process your payment');
} catch (InvalidArgumentException $e) {
// Обработка ошибок валидации
return Response::validationError($e->getMessage());
} catch (Throwable $e) {
// Универсальный перехват всех ошибок (PHP 7+)
$logger->critical('Unexpected error', ['exception' => $e]);
throw new InternalServerErrorException();
} finally {
// Всегда выполняется
$processor->cleanup();
}
2. Иерархия исключений
Современные фреймворки используют сложные иерархии:
namespace App\Exceptions;
// Базовое исключение приложения
abstract class AppException extends \RuntimeException
{
protected $context = [];
public function withContext(array $context): self
{
$this->context = $context;
return $this;
}
}
// Специализированные исключения
class ValidationException extends AppException
{
protected $errors = [];
public function __construct(array $errors, string $message = 'Validation failed')
{
$this->errors = $errors;
parent::__construct($message, 422);
}
}
class NotFoundException extends AppException
{
public function __construct(string $message = 'Resource not found')
{
parent::__construct($message, 404);
}
}
3. Глобальный обработчик ошибок
PHP 7+ предоставляет set_exception_handler() и set_error_handler():
set_error_handler(function ($severity, $message, $file, $line) {
if (!(error_reporting() & $severity)) {
return false;
}
throw new \ErrorException($message, 0, $severity, $file, $line);
});
set_exception_handler(function (Throwable $exception) {
$logger = App::getLogger();
$logger->emergency('Uncaught exception', [
'exception' => $exception,
'trace' => $exception->getTraceAsString()
]);
if (php_sapi_name() === 'cli') {
fwrite(STDERR, "Error: " . $exception->getMessage() . PHP_EOL);
} else {
http_response_code(500);
echo json_encode(['error' => 'Internal server error']);
}
});
4. Логирование и мониторинг
PSR-3 стандарт для логирования — обязателен для современного приложения:
use Psr\Log\LoggerInterface;
class Service
{
private LoggerInterface $logger;
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
public function process(array $data): void
{
try {
$this->logger->info('Processing started', ['data' => $data]);
// Бизнес-логика
} catch (RuntimeException $e) {
$this->logger->error('Processing failed', [
'exception' => $e,
'data' => $data,
'context' => ['user_id' => $this->userId]
]);
throw $e;
}
}
}
5. Обработка в асинхронном коде
Для асинхронных операций (ReactPHP, Amp, Swoole):
// Пример с промисами
$promise = asyncOperation()
->then(function ($result) {
// Успешная обработка
return processResult($result);
})
->otherwise(function (Throwable $error) {
// Обработка ошибок
if ($error instanceof ConnectionException) {
return retryOperation();
}
throw $error;
})
->always(function () {
// cleanup логика
});
6. Best Practices
- Используйте типизированные исключения для разных сценариев (доменные, инфраструктурные)
- Не ловите исключения, которые не можете обработать — позвольте им всплывать
- Всегда логируйте с контекстом — включайте ID пользователя, запроса, параметры
- В production показывайте пользователю общие сообщения, а детали — только в логи
- Используйте мониторинг (Sentry, Bugsnag, Rollbar) для отслеживания ошибок в реальном времени
- Пишите unit-тесты для проверки поведения при ошибках
7. Обработка в REST API
// Глобальный middleware для API
class ErrorHandlerMiddleware
{
public function handle(Request $request, Closure $next): Response
{
try {
return $next($request);
} catch (ValidationException $e) {
return response()->json([
'error' => 'validation_error',
'messages' => $e->getErrors()
], 422);
} catch (AuthenticationException $e) {
return response()->json([
'error' => 'authentication_required'
], 401);
} catch (Throwable $e) {
// Логирование
Log::error($e);
// Production vs development
if (app()->environment('production')) {
return response()->json(['error' => 'server_error'], 500);
}
return response()->json([
'error' => $e->getMessage(),
'trace' => $e->getTrace()
], 500);
}
}
}
Современная обработка ошибок в PHP — это комбинация исключений, PSR-стандартов, централизованного логирования и специализированных инструментов мониторинга. Ключевой принцип: ошибки должны быть предсказуемыми, обрабатываемыми и отслеживаемыми на всех уровнях приложения.