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

Как устроена работа исключений в PHP 7?

1.7 Middle🔥 131 комментариев
#PHP Core

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

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

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

Устройство исключений в PHP 7

Исключения (Exceptions) в PHP 7 представляют собой объектно-ориентированный механизм обработки ошибок, который позволяет отделить нормальный поток выполнения программы от обработки нештатных ситуаций. В отличие от PHP 5, где исключения и ошибки были разными сущностями, PHP 7 ввел единую иерархию исключений через интерфейс Throwable.

Иерархия исключений

В PHP 7 все бросаемые сущности реализуют интерфейс Throwable:

interface Throwable {
    public function getMessage(): string;
    public function getCode(): int;
    public function getFile(): string;
    public function getLine(): int;
    public function getTrace(): array;
    public function getTraceAsString(): string;
    public function getPrevious(): ?Throwable;
    public function __toString(): string;
}

Конкретные классы исключений:

  • Exception - базовый класс для пользовательских исключений
  • Error - базовый класс для фатальных ошибок PHP (нововведение PHP 7)

Пример иерархии:

Throwable
├── Exception
│   ├── LogicException
│   │   ├── InvalidArgumentException
│   │   └── RuntimeException
│   │       └── OutOfBoundsException
│   └── PDOException
└── Error
    ├── TypeError
    ├── ParseError
    ├── ArithmeticError
    │   └── DivisionByZeroError
    └── AssertionError

Ключевые изменения в PHP 7

  1. Единая иерархия Throwable - все ошибки и исключения реализуют один интерфейс
  2. EngineException заменены на Error - фатальные ошибки теперь бросаются как объекты Error
  3. Строгая типизация для аргументов и возвращаемых значений - приводит к TypeError

Механизм работы

Бросок исключения

function divide(int $a, int $b): float {
    if ($b === 0) {
        throw new DivisionByZeroError('Division by zero is not allowed');
    }
    return $a / $b;
}

Перехват исключений

try {
    $result = divide(10, 0);
} catch (DivisionByZeroError $e) {
    echo "Математическая ошибка: " . $e->getMessage();
} catch (Throwable $e) {
    echo "Общая ошибка: " . $e->getMessage();
} finally {
    echo "Этот блок выполнится всегда";
}

Особенности реализации

Цепочка исключений

PHP поддерживает цепочку исключений через третий параметр конструктора:

try {
    try {
        throw new Exception('Первоначальная ошибка');
    } catch (Exception $e) {
        throw new RuntimeException('Новая ошибка', 100, $e);
    }
} catch (Throwable $e) {
    echo $e->getMessage() . "\n";
    echo "Предыдущее исключение: " . $e->getPrevious()->getMessage();
}

Пользовательские исключения

Можно создавать собственные иерархии исключений:

class ValidationException extends InvalidArgumentException {
    private array $errors;
    
    public function __construct(string $message, array $errors = []) {
        parent::__construct($message);
        $this->errors = $errors;
    }
    
    public function getErrors(): array {
        return $this->errors;
    }
}

Обработка фатальных ошибок

В PHP 7 даже фатальные ошибки стали исключениями:

try {
    // Вызов несуществующей функции
    nonExistentFunction();
} catch (Error $e) {
    echo "Перехвачена фатальная ошибка: " . $e->getMessage();
}

Глобальный обработчик исключений

Можно установить глобальный обработчик для неперехваченных исключений:

set_exception_handler(function (Throwable $e) {
    error_log("Неперехваченное исключение: " . $e->getMessage());
    http_response_code(500);
    echo "Внутренняя ошибка сервера";
});

// Или восстановить стандартный обработчик
restore_exception_handler();

Производительность

Важное улучшение в PHP 7 - механизм исключений стал значительно быстрее благодаря:

  • Оптимизации внутренней структуры zend_exception
  • Уменьшению накладных расходов на бросок исключения
  • Более эффективному хранению трассировки стека

Сравнение с PHP 5

// PHP 5: ошибки и исключения обрабатывались по-разному
set_error_handler(function($errno, $errstr) {
    throw new ErrorException($errstr, 0, $errno);
});

// PHP 7: единый подход через Throwable
try {
    include 'non_existent_file.php';
} catch (Throwable $e) {
    // Перехватит как ParseError, так и другие исключения
}

Рекомендации по использованию

  1. Всегда ловите Throwable на верхнем уровне приложения
  2. Используйте конкретные типы исключений для точной обработки
  3. Не злоупотребляйте исключениями для контроля потока выполнения
  4. Логируйте исключения с полной информацией (сообщение, стек вызовов)
  5. Используйте finally для освобождения ресурсов

Пример комплексной обработки

class ExceptionHandler {
    public static function handle(Throwable $e): void {
        // Логирование
        error_log(sprintf(
            "[%s] %s in %s:%d\nStack trace:\n%s",
            get_class($e),
            $e->getMessage(),
            $e->getFile(),
            $e->getLine(),
            $e->getTraceAsString()
        ));
        
        // Пользовательский вывод (в зависимости от среды)
        if (php_sapi_name() === 'cli') {
            echo "Ошибка: " . $e->getMessage() . "\n";
        } else {
            http_response_code(500);
            if (defined('DEBUG') && DEBUG) {
                echo "<pre>" . htmlspecialchars((string)$e) . "</pre>";
            } else {
                echo "Произошла ошибка. Администратор уведомлен.";
            }
        }
    }
}

// Установка глобального обработчика
set_exception_handler([ExceptionHandler::class, 'handle']);

Механизм исключений в PHP 7 представляет собой зрелую, производительную систему, которая объединила обработку ошибок и исключений в единую иерархию, что делает код более предсказуемым и удобным для поддержки.

Как устроена работа исключений в PHP 7? | PrepBro