Статьи

Ускоренный ход изменений в обработке исключений в PHP 7

Эта статья была рецензирована Томасом Пунтом , Никласом Келлером и Юнесом Рафи . Спасибо всем рецензентам SitePoint за то, что сделали контент SitePoint как можно лучше!

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

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

Бросаемый класс

Throwable — это интерфейс, от которого разветвляются классы Exception и Error . Этот конкретный класс помогает вам отлавливать любые бросаемые ошибки, независимо от того, являются ли они исключением или ошибкой. Например:

<?php try { throw new Exception("This is an exception"); } catch (Throwable $e) { echo $e->getMessage(); } 

Или только что определенный ParseError :

 <?php try { $result = eval("2*'7'"); } catch (Throwable $e) { echo $e->getMessage(); } 

После выполнения этого кода вы получите ParseError, потому что внутри eval() отсутствует «;» .

Пользовательские классы не Throwable напрямую реализовывать Throwable и вместо этого должны расширять Exception которое реализует Throwable .

Класс ошибки

Класс Error в PHP 7 — это новый тип класса, который обрабатывает различные ошибки — это либо фатальные ошибки, либо ошибки типа, и этот класс предназначен только для внутренних ошибок PHP. Ошибка делится на четыре подкласса:

  1. ArithmeticError
  2. TypeError
  3. ParseError
  4. AssertionError

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

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

ArithmeticError

Эта ошибка появляется при выполнении математических операций. Например, когда вы используете intdiv() :

 <?php try { var_dump(intdiv(PHP_INT_MIN, -1)); } catch (ArithmeticError $e) { echo $e->getMessage(); } 

Вы получите « Деление PHP_INT_MIN на -1 », потому что мы немного сместили его на отрицательную величину.

Другой класс, DivisionByZeroError , также происходит от ArithmeticError . Эта ошибка возникает при двух разных условиях:

Примечание . Вы получите -1 только в сочетании с PHP_INT_MIN .

Во-первых, если вы делаете мод числа на 0:

 <?php try { $result = 5 % 0; echo $result; } catch (DivisionByZeroError $e) { echo $e->getMessage(); } 

Если вы используете тот же метод, что и выше, и измените % на / , вместо этого вы получите предупреждение, результатом которого может быть любой из них: +INF , -INF или NAN . Если вы хотите, чтобы это привело к исключению, лучше использовать обработчик ошибок, который преобразует предупреждение в выброшенное исключение.

Однако у вас будет исключение DivisionByZeroError, если вы выполните следующий код:

 <?php try { $result = is_finite(1.0 / 0); if (in_array($result, [INF, NAN,-INF])) { throw new DivisionByZeroError('Division by zero error'); } } catch (DivisionByZeroError $e) { echo $e->getMessage(); } 

Другой метод, который получит вам DivisionByZeroError,intdiv() снова использовать intdiv() .

Примечание . Отчет об ошибке для этой проблемы был опубликован на PHP.net.

TypeError

Эта ошибка в основном используется с объявлениями скалярных типов в PHP 7. Эта ошибка будет отображаться, когда вы создали функцию или переменную определенного типа данных и пытаетесь сохранить значение другого типа данных. Например:

 <?php declare (strict_types = 1); function add(int $a, int $b) { return $a + $b; } try { echo add("3", "4"); } catch (TypeError $e) { echo $e->getMessage(); } 

Если вы запустите приведенный выше код, будет TypeError , и вы получите, must be of the type integer, string was given ошибку. Если вы запустите приведенный выше код без declare(strict_types=1); у вас не возникнет никаких проблем, и результат будет 7, если вы не измените число на нечисловую строку.

ParseError

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

 <?php $a = 4 $result = $a * 5; 

И мы называем это в другом файле PHP:

 <?php try { require "index3.php"; } catch (ParseError $e) { echo $e->getMessage(); } 

При выполнении этого кода вместо фатальной ошибки отображается syntax error, unexpected end of file . До того, как этот класс был представлен, было почти невозможно обрабатывать синтаксические и фатальные ошибки с легкостью.

AssertionError

Перед введением класса AssertionError нам пришлось создать собственные функции для обработки исключений утверждений при привязке пользовательской функции с помощью assert_options (). Эта ошибка будет отображаться только в том случае, если утверждение, выполненное с помощью assert() не будет выполнено. Для работы с ним сначала необходимо настроить директивы assert в PHP.ini :

  1. Assert.exception: по умолчанию его значение равно 0, и он генерирует только предупреждение для объекта, а не показывает ошибку. Однако, когда значение изменяется на 1, оно генерирует исключение или ошибку подтверждения, которая может быть перехвачена.

  2. Zend.assertions: по умолчанию его значение равно -1, что для производственного режима, т. Е. Код подтверждения не будет сгенерирован. Когда он установлен в 1, он будет в режиме разработки, в котором код подтверждения будет сгенерирован и выполнен. Когда он установлен в 0 , код подтверждения будет сгенерирован, но не будет выполнен во время выполнения.

Например, давайте сделаем утверждение, которое потерпит неудачу.

 <?php try { assert(2 < 1, "Two is less than one"); } catch (AssertionError $ex) { echo $ex->getMessage(); } 

Когда приведенный выше код будет выполнен, вы получите только предупреждение: "assert(): Two is less than one failed" и ваше исключение не будет assert.exception поскольку assert.exception равно 0. Чтобы заставить AssertionError перехватить исключение assert, нам нужно изменить assert.exception на 1. Итак, когда вы запускаете следующий код:

 <?php ini_set('assert.exception', 1); try { assert(2 < 1, "Two is not less than one"); } catch (AssertionError $ex) { echo $ex->getMessage(); } 

Вместо предупреждения вы увидите, что ошибка обнаружена, и будет показано только сообщение об ошибке, т.е. «Два меньше одного».

С момента появления новых классов многие фатальные и восстанавливаемые фатальные ошибки были унаследованы от класса Error. Не гарантируется, что ваш пользовательский обработчик, который вы установили с помощью set_exception_handler() , будет ловить эти ошибки. Итак, если вы хотите добавить некоторые пользовательские исключения в ваш код, вам не нужно сбрасывать свой собственный обработчик, поскольку теперь он может перехватывать ошибки, просто используя Throwable .

Резюме

Если вы используете версию PHP старше 7 лет, вы должны помнить об этом перед переходом. Чтобы быть в безопасности, вы также можете посмотреть руководство по обновлению php 7 .

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