#10. 5 php Исключения. Базовый синтаксис try...catch. Инструкция throw. Раскрутка стека вызова функций. Глобальный обработчик
Primary tabs
Исключение — это объект некоторого класса, который содержит в себе сведения о возникшей в процессе выполнения программы ошибке или исключительной ситуации, необходимые для её обработки.
Все исключения, генерируемые внутренними PHP-функциями, наследуются от стандартного класса Error. Например, при выполнении
<?php echo 1/0;
будет "выброшено" исключение встроенного типа DivisionByZeroError.
А все новые пользовательские типы исключений должны наследоваться от базового класса Exception :
<?php class myException extends Exception { }
Оба класса, Error
и Exception
, реализуют интерфейс Throwable.
Базовый синтаксис. Конструкция try..catch
Код, который проверяется на наличие ошибок, нарушающих логику алгоритма, помещается в блок try
. Блок catch
отвечает за обработку исключений, совместимых по присваиванию с его аргументом (то есть объектов того же класса или наследников). Любые исключения можно поймать, указав Throwable
.
Пример 1. Обработка автоматически генерируемого PHP исключения
<?php for ($i=0; $i<100; $i++) { try { echo 1/mt_rand(-5, 5), "<BR>"; } catch (Throwable $e) { echo $e->getMessage(), "<BR>"; } }
В приведенном демонстрационном примере 1 в цикле for
выполняется деление на случайное число от -5 до 5. Соответствующая инструкция помещается в блок try
. В случае деления на ноль автоматически генерируется исключение и передается в блок catch
, в котором с помощью метода getMessage()
, предоставляемого интерфейсом Throwable
, выводится стандартное сообщение об ошибке данного типа. При этом программа не прерывается, и после обработки исключения в блоке catch
выполняется переход к следующей итерации цикла.
Несколько блоков catch
Блоку try
может соответствовать сколько угодно блоков catch
, отвечающих за обработку различных типов исключений:
<?php try { //какой-то код } catch (myException $e) { echo $e->getMessage(); } catch (Exception $e) { error_log($e->getMessage()); }
Если исключение не может быть обработано первым блоком catch
, то оно будет передано дальше: во второй и т.д.
Если же предполагается одинаковая обработка для разных типов исключений, то, начиная с версии PHP 7.1.0, их можно указать в одном блоке catch
, используя символ |
:
<?php try { //какой-то код } catch (myException | myOtherException) { //обработка выброшенного исключения }
Инструкция throw
Явно сгенерировать исключение можно с помощью ключевого слова throw
. Например, пользователь, заполняя данные формы, забыл указать какое-то обязательное поле. В этом случае можно сгенерировать исключение специального типа.
Пример 2. Использование throw
для генерации пользовательского исключения
class KeyFieldMissingException extends Exception { public function __(string $name) { parent::__construct("Поле $name обязательно для заполнения"); } } function validateUserData() { $keyFields = array("Имя", "Номер телефона"); foreach ($keyFields as $field) { if ($_REQUEST[$field] == "") { throw new KeyFieldMissingException($field); } } }
Раскрутка стека вызовов функций
В приведенном выше примере 2 отсутствует конструкция try..catch
. Это допустимо, если функция validateUserData()
, выбрасывающая исключение, вызывается из блока try
другой функции или основной программы. Например,
<?php function saveUserData() { echo "Данные успешно сохранены."; } try { validateUserData(); saveUserData(); } catch (Exception $ex) { echo "Не удалось сохранить данные: " . $ex->getMessage(); }
Результатом выполнения данного кода будет сообщение об успешном сохранении данных пользователя, если обе функции внутри блока try
отработают без ошибок. Если же одно из обязательных полей не было заполнено, то в функции validateUserData()
будет выброшено исключение и передано для обработки в блок catch
. Результатом в этом случае будет строка типа
Не удалось сохранить данные: Поле Номер телефона обязательно для заполнения
Процесс передачи выброшенного исключения из вложенной функции блока try
(любого уровня вложенности) в блок catch
, в котором данное исключение должно быть обработано, минуя все промежуточные уровни, называется раскруткой стека вызовов функций.
Замечание
Код блока try
, который следует после генерации исключения, игнорируется. Таким образом, выброшенное исключение прерывает выполнение операции, которая уже пошла не так, и при этом не завершается работа программы в целом.
Глобальный обработчик исключений
По идее инструкция throw
должна всегда выполняться в рамках некоторого блока try
, а выброшенное исключение должно быть обязательно перехвачено в соответствующем блоке catch
. Однако технически можно использовать throw
в любом месте программы, или выбросить исключение такого типа, для которого блок catch
не предусмотрен. Кроме того, исключения могут генерироваться и автоматически, внутренними PHP функциями.
Для неперехваченных ни в одном блоке catch
исключений можно установить глобальный обработчик с помощью функции set_exception_handler()
:
<?php function myExceptionHandler(Throwable $e) { echo "Неперехваченное исключение: " . $e->getMessage(); } set_exception_handler('myExceptionHandler'); echo 1/0;
Если глобальный обработчик не установлен, то неперехваченное исключение аварийно завершает работу программы.
Конструкция try..finally
Блок finally
может быть указан после или вместо блоко catch
. Блок finally
будет выполнен в любом случае после выполнения try
и catch
, не зависимо от того, было ли выброшено исключение. Блок finally
выполняется и в том случае, если выполнение блока catch
прерывается инструкцией throw
.
<?php try { echo "Внешний блок try<BR>"; try { echo "Вложенный блок try<BR>"; throw new Exception(); } catch (Exception $e) { echo "Вложенный блок catch. Пробрасываем исключение дальше<BR>"; throw $e; } finally { echo "Блок finally<BR>"; } } catch (exception $e) { echo "Внешний блок catch<BR>"; }
Результат:
Внешний блок try Вложенный блок try Вложенный блок catch. Пробрасываем исключение дальше Блок finally Внешний блок catch
- Log in to post comments
- 922 reads