Каким типом данных представлено исключение (Exception) в PHP?

Ответ

В PHP исключения представлены объектами. Базовым классом для всех исключений является встроенный класс Exception или, начиная с PHP 7, интерфейс Throwable, который он реализует.

Пример базовой обработки:

try {
    if ($file === null) {
        throw new InvalidArgumentException('Файл не указан.');
    }
    $content = file_get_contents($file);
} catch (InvalidArgumentException $e) {
    // Ловим конкретный тип исключения
    echo 'Ошибка аргумента: ' . $e->getMessage();
    log_error($e->getFile(), $e->getLine());
} catch (Exception $e) {
    // Ловим все остальные исключения
    echo 'Произошла общая ошибка: ' . $e->getMessage();
}

Класс Exception предоставляет методы для отладки:

  • getMessage() — сообщение об ошибке.
  • getCode() — числовой код ошибки.
  • getFile(), getLine() — место возникновения.
  • getTrace(), getTraceAsString() — стек вызовов.

Создание пользовательского исключения:

class ConfigurationException extends RuntimeException
{
    protected $configKey;

    public function __construct(string $key, string $message = '', int $code = 0, Throwable $previous = null)
    {
        $this->configKey = $key;
        parent::__construct($message ?: "Ошибка в конфигурационном ключе: {$key}", $code, $previous);
    }

    public function getConfigKey(): string
    {
        return $this->configKey;
    }
}

// Использование
throw new ConfigurationException('database.host');

Ответ 18+ 🔞

Давай разберем, как в PHP с этими исключениями работать, а то там порой такой пиздец творится, что волосы дыбом встают. Представь, что исключения — это просто объекты, ну как коробки, в которые запихнули ошибку и кинули тебе в голову. Базовый класс для всей этой движухи — Exception, а с седьмой версии PHP ещё и интерфейс Throwable появился, который этот класс реализует. В общем, хуй с горы, главное — понять принцип.

Вот смотри, как это обычно выглядит на практике:

try {
    if ($file === null) {
        throw new InvalidArgumentException('Файл не указан.');
    }
    $content = file_get_contents($file);
} catch (InvalidArgumentException $e) {
    // Ловим конкретный тип исключения
    echo 'Ошибка аргумента: ' . $e->getMessage();
    log_error($e->getFile(), $e->getLine());
} catch (Exception $e) {
    // Ловим все остальные исключения
    echo 'Произошла общая ошибка: ' . $e->getMessage();
}

Суть в чём: ты пытаешься выполнить код в try, и если там что-то пошло не так — выкидываешь исключение командой throw. А потом ловишь его в catch, как какого-нибудь жулика. Можно ловить конкретные типы, например, InvalidArgumentException, а можно и все подряд через общий Exception. Удобно, ёпта.

У самого объекта исключения есть куча полезных методов, чтобы понять, где и что наебнулось:

  • getMessage() — собственно, текст ошибки, который ты сам и написал.
  • getCode() — какой-то числовой код, если нужен.
  • getFile(), getLine() — файл и строка, где всё полетело к чертям. Без этого иногда вообще нихуя не понятно.
  • getTrace(), getTraceAsString() — стек вызовов, то есть полная история, кто кого вызывал перед тем, как всё накрылось медным тазом. Для отладки — самое то.

А теперь самое интересное — можно свои собственные исключения наколдовать. Это когда стандартные тебе не подходят, и ты хочешь запихнуть в ошибку ещё какую-то свою информацию. Выглядит это примерно так:

class ConfigurationException extends RuntimeException
{
    protected $configKey;

    public function __construct(string $key, string $message = '', int $code = 0, Throwable $previous = null)
    {
        $this->configKey = $key;
        parent::__construct($message ?: "Ошибка в конфигурационном ключе: {$key}", $code, $previous);
    }

    public function getConfigKey(): string
    {
        return $this->configKey;
    }
}

// Использование
throw new ConfigurationException('database.host');

Создал класс ConfigurationException, который наследуется от RuntimeException. В конструктор передаёшь ключ конфига, а потом можешь его через getConfigKey() вытащить. Получается не просто «чё-то сломалось», а конкретно «сломалось вот тут, в настройке базы данных». Красота, ядрёна вошь! Теперь твоя ошибка сама расскажет, в чём дело, а не будет загадкой, как пизда с ушами. Главное — не забудь потом это исключение поймать, а то оно так и будет лететь наверх, пока скрипт не сдохнет с позором.