PHP

Обработка ошибок и исключений в PHP

06 Декабря 2023 (ред)

После выхода PHP 7 механизм встроенных ошибок был сильно изменён и теперь представляет собой разделение на классы Error (Фатальная ошибка) и Exception (Исключение). Первый содержит перечень унаследованных от него типизированных классов для фатальных ошибок PHP, а Exception должен содержать исключения с возможностью обработки, которые будут от него унаследованы. Вместе эти два основных класса объединены интерфейсом Throwable, соответственно и все их потомки. Поэтому абсолютно все ошибки и исключения в PHP имеют общий интерфейс.

Фатальная ошибка отличается от исключения в данном контексте тем, что в первом случае произошла ошибка совместимости с правильным разбором кода PHP, компиляции этого кода, а также нарушением математических правил, а в качестве исключения подразумеваются ошибки в коде, нарушающие логику приложения, неправильные данные в качестве аргументов из внешних источников, а также остальные, не являющиеся внутренними ошибками PHP, которые могут быть перехвачены и обработаны в коде. Обработать технически можно и ошибки из раздела Error, если необходимо, например, уточнить дефолтное сообщение и вызвать это же исключение далее или сохранить в особый лог, но в обычном режиме работы приложения трудно представить продолжение его нормальной работы с изначально допущенными ошибками в синтаксисе PHP или нарушением математических правил.

Обработка ошибок

Примеры обработки фатальной ошибки с помощью блока try/catch:


try {
  $i =  1 / 0;
} catch (Error $e) {
   die($e->getMessage() . ' / ' . $e::class);
}
// Division by zero / DivisionByZeroError

try {
  $i = count(1);
} catch (Error $e) {
   die($e->getMessage() . ' / ' . $e::class);
}
// count(): Argument #1 ($value) must be of type Countable|array, int given / TypeError

Принцип обработки исключений в блоке try/catch, как в примере выше, состоит в в том, что если возникает ошибка или исключение, то выполнение скрипта обращается выше по стеку вызовов к первому найденному блоку try/catch, действие которого распространяется на эту ошибку, и будет им обработано. В случае, если такой блок не будет найден, то ошибка будет обработана как стандартная ошибка PHP.

При возникновения исключения, например, аргумент другого типа, чем назначен в функции или методе, это исключение логически может быть частью исправно работающей программы, в таком случае перехваченное исключение может направить выполнение по другому пути, к примеру, проинформировав источник этих данных соответствующим образом или инициировав иное подходящее действие.

Блок try/catch может быть многосоставным, как на следующем примере:

try {   
   throw new ErrorException('Custom message');    
} catch (AssertException|RuntimeException) {   
   echo 'AssertException or RuntimeException type';   
} catch (Exception) {   
   echo 'Exception type';   
} catch (Throwable) {   
   echo 'Throwable interface';  
} finally { 
   echo ' and Finally';
}
// Exception type and Finally

Указать несколько классов через оператор '|' и не использовать переменную в условии catch можно в версии PHP 8.0 и выше.

Вместо обрабатываемого кода в примере вызывается предопределённое исключение ErrorException с помощью выражения throw. В первом разделе блока обработчика назначены классы AssertException или RuntimeException, поэтому он будет пропущен, так как не подходит. В втором разделе класс Exception который является родительским классом для ErrorException, поэтому и будет использован. В разделе обработчика с Throwable могли быть обработаны оставшиеся ошибки, в данном случае все подтипы Error. Раздел finally будет выполнен в любом случае, как видно из результата, даже если ошибка не произошла или не была перехвачена.

Таким образом, ошибки информируют о фатальных происшествиях при компиляции/выполнении кода, а исключения возникают только во время выполнения кода. Обработчики ошибок позволяют охватить проверками участки кода и реагировать определенным образом на произошедшие там ошибки по их типу.

Обработка ошибок может быть задана и назначением глобальных пользовательских обработчиков, например при помощи функции set_error_handler(), подробнее здесь.

Иерархия классов ошибок (PHP 8.3)

Throwable
    Error
        ArithmeticError
            DivisionByZeroError
        AssertionError
        CompileError
            ParseError
        DateError
            DateObjectError
            DateRangeError
        FiberError
        Random\RandomError
            Random\BrokenRandomEngineError
        TypeError
            ArgumentCountError
        UnhandledMatchError
        ValueError
    Exception
        ClosedGeneratorException
        DateException
            DateInvalidOperationException
            DateInvalidTimeZoneException
            DateMalformedIntervalStringException
            DateMalformedPeriodStringException
            DateMalformedStringException
        DOMException
        ErrorException
        IntlException
        JsonException
        LogicException
            BadFunctionCallException
                BadMethodCallException
            DomainException
            InvalidArgumentException
            LengthException
            OutOfRangeException
        PharException
        Random\RandomException
        ReflectionException
        RuntimeException
            OutOfBoundsException
            OverflowException
            PDOException
            RangeException
            UnderflowException
            UnexpectedValueException
        SodiumException
        SQLite3Exception

Throwable

Throwable является родительским интерфейсом для всех классов ошибок и объектов на их основе, вызываемых с помощью выражения throw и включает классы Error и Exception.

Согласно общему интерфейсу Throwable все унаследованные классы имеют минимальный набор методов для управления ошибкой или исключением. Некоторые классы расширяют этот набор собственными методами.

getMessage — Получает сообщение ошибки/исключения.

getCode — Возвращает код ошибки/исключения.

getFile — Возвращает файл, в котором возникла ошибка/исключение.

getLine — Получает строку скрипта, в которой данный объект был вызван.

getTrace — Возвращает трассировку стека.

getTraceAsString — Получает результаты трассировки стека в виде строки.

getPrevious — Возвращает предыдущий Throwable.

__toString — Получает строковое представление вызванного объекта.

Error

Базовый класс для всех внутренних ошибок PHP.

Реализует дополнительный метод __clone — Клонирование ошибки.

ArithmeticError

ArithmeticError вызывается в случаях, когда возникает ошибка при выполнении математических операций.

DivisionByZeroError Имея родительский класс ArithmeticError, эта ошибка вызывается при делении на ноль.

AssertionError

AssertionError вызывается, когда утверждение, сделанное с помощью assert(), терпит неудачу.

CompileError

Используется для ошибок, возникающих при компиляции PHP-кода.

ParseError Наследуясь от CompileError, эта уточняющая ошибка вызывается, когда возникает ошибка при разборе PHP-кода, например, как результат вызова функции eval().

DateError

Вызывается в случаях, когда не удается определить часовой пояс или интервал для даты содержит недопустимые значения.

DateObjectError Подтип DateError, вызывается при ошибке программиста, когда класс Date/Time не был правильно инициализирован.

DateRangeError Вызывается на 32-битных платформах, если объект даты представляет дату за пределами 32-битного знакового диапазона.

FiberError

Вызывается при недопустимой операции при использовании файбера (см. Fiber).

Random\RandomError

Базовый класс для ошибок , возникающих во время генерации или использования случайных чисел.

Random\BrokenRandomEngineError Указывает на ошибочность текущего механизма Random\Engine, например, из-за сильного смещения в результате генерации.

TypeError

Вызывается при несоответствии присваиваемых данных по типу для свойств классов, аргументам методов и функций или неправильному типу возвращаемых значений.

ArgumentCountError Унаследованный от TypeError, этот класс сигнализирует об ошибке, когда в пользовательский метод или функцию передано недостаточное количество аргументов. Эта ошибка также выбрасывается, если в невариативную встроенную функцию передаётся слишком много аргументов.

UnhandledMatchError

UnhandledMatchError вызывается, когда субъект, переданный в регулярное выражение match, не обрабатывается ни одним из условий регулярного выражения.

ValueError

Ошибка ValueError вызывается если тип аргумента правильный, но его значение неверно. Например, передача отрицательного целого числа, когда функция ожидает положительное, или передача пустого массива, когда функция ожидает, что он не будет пустым.

Exception

Базовый класс для всех пользовательских исключений.

Реализует дополнительный метод __clone — Клонирование исключения.

ClosedGeneratorException

Когда в генераторе закончатся значения, запрос нового значения вызовет это исключение.

DateException

Родительский класс исключений Date/Time для проблем, которые обнаруживаются из-за неверного ввода данных пользователем, или аргументов произвольной формы, которые необходимо проанализировать.

DateInvalidOperationException Вызывается DateTimeImmutable::sub() и DateTime::sub(), вычитающих определённое значение времени (день, неделю, месяц и тд), при попытке выполнения неподдерживаемой операции.

DateInvalidTimeZoneException Вызывается, когда в DateTimeZone::construct() передается неверное значение.

DateMalformedIntervalStringException Вызывается, когда в DateInterval::construct() передается недопустимый аргумент duration.

DateMalformedPeriodStringException Вызывается, когда в DateInterval::construct()передается недопустимый аргумент isostr.

DateMalformedStringException Вызывается при обнаружении недопустимого строкового значения Date/Time.

DOMException

Операции DOM при определённых обстоятельствах выбрасывают исключения, например, когда выполнение операции невозможно по понятным причинам. Уточнение: модуль DOM позволяет работать с XML-документами через DOM API с PHP.

ErrorException

Класс для создания пользовательской ошибки, включающей задание уровня серьезности этой ошибки.

Дополнительный метод: getSeverity — возвращает числовую степень серьёзности исключения, которая может быть установлена в конструкторе.

IntlException

Этот класс служит для вызова исключений в случае возникновения ошибки в функциях intl (интернационализации). Данные исключения могут быть вызваны только если включена опция intl.useexceptions.

JsonException

Данное исключение выбрасывается, если опция JSON_THROW_ON_ERROR установлена для функции json_encode() или json_decode().

LogicException

Исключение, которое представляет ошибку в логике программы. В документации указано, что такой тип исключений должен непосредственно привести к исправлениям в вашем коде.

BadFunctionCallException Это исключение вызывается, если callback-функция относится к неопределённой функции или если некоторые аргументы отсутствуют.

BadMethodCallException Унаследованный от BadFunctionCallException, этот класс ошибки вызывается, если callback-функция относится к неопределённому методу или если некоторые аргументы отсутствуют.

DomainException Создаётся исключение, если значение не соответствует определённой допустимой области данных. В программировании термин "домен" обычно относится к контексту или области применения, где определены определенные правила, ограничения или допустимые значения. Например, попытка выполнить действие, которое не соответствует допустимым правилам для данного объекта или контекста, может вызвать исключение типа DomainException.

InvalidArgumentException Вызывается исключение, если аргумент не соответствует ожидаемому типу.

LengthException Это исключение применяется в случае, если длина значения является недопустимой.

OutOfRangeException По определению, OutOfRangeException следует использовать, когда потенциальная проблема является логической — возникает из-за неправильного кода или определения, обнаруженная при выполнении программы, например, отсутствие необходимого поля в получении данных из БД.

PharException

Класс PharException предоставляет класс исключения модуля phar для блоков try/catch. Примечание: модуль phar предоставляет возможность поместить целое PHP-приложение в один-единственный файл c именем phar (PHP Archive) для простого распространения и установки.

Random\RandomException

Базовый класс для исключений Exception, возникающих при генерации или использовании случайной последовательности.

ReflectionException

Класс для вывода ошибок связанных с рефлексией в PHP. Уточнение: рефлексия в PHP предоставляет возможность обращаться напрямую к структуре классов, интерфейсов, функций, методов и модулей. Кроме того, Reflection API позволяет получать doc-блоки комментариев функций, классов и методов.

RuntimeException

Это исключение вызывается в случае возникновения ошибки, которая может быть найдена только во время выполнения. Все исключения Exception вызываются во время выполнения, но в данном случае имеется в виду то, что ошибка может быть обнаружена только в результате выполнения кода, будь то нестандарный внешний набор данных или иные возможные, но не обязательно возникающие условия .

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

OverflowException Сигнализирует о переполнении некоего набора ограниченных по размеру данных.

PDOException Представляет ошибку, вызванную PDO (Модуль объекта данных). Согласно документации, не следует выбрасывать собственные исключения PDOException из кода.

RangeException Версия DomainException, но возникающая во время выполнения программы.

UnderflowException Сигнализирует о недопустимой операции над пустым хранилищем данных (массив, контейнер и тд).

UnexpectedValueException Вызывается исключение, если значение не совпадает с ожидаемым набором значений.

SodiumException

Исключения, выбрасываемые функциями sodium (программная библиотека для шифрования, дешифрования, подписи, хеширования паролей и многого другого).

SQLite3Exception

Исключения связанные с SQLite 3 базой данных.

Для ответа вы можете авторизоваться


Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.