← Назад к вопросам

Как обрабатывать ошибки в современном PHP?

2.0 Middle🔥 181 комментариев
#PHP Core#Архитектура и паттерны

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Современные подходы к обработке ошибок в 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-стандартов, централизованного логирования и специализированных инструментов мониторинга. Ключевой принцип: ошибки должны быть предсказуемыми, обрабатываемыми и отслеживаемыми на всех уровнях приложения.

Как обрабатывать ошибки в современном PHP? | PrepBro