PHP Учебник

PHP Старт Введение в PHP Установка PHP Синтаксис PHP Комментарии в PHP Переменные PHP PHP Echo / Print Типы данных PHP Строки PHP Числа PHP Математика в PHP Константы PHP Операторы PHP PHP If...Else...Elseif PHP Switch Циклы в PHP Функции PHP Массивы PHP PHP Суперглобальные PHP RegEx

PHP Формы

Обработка форм PHP Валидация форм PHP Обязательные поля Валидация URL/E-mail Полная форма PHP

PHP Продвинутый

PHP Дата и время PHP Include/Require PHP Работа с файлами Открытие/Чтение файлов Создание/Запись файлов PHP Загрузка файлов Файлы cookie PHP Сессии PHP Фильтры PHP Расширенные фильтры PHP Функция Callback PHP JSON PHP Исключения

PHP OOP

Что такое ООП в PHP Классы/Объекты PHP Цепочки методов PHP Конструктор PHP Деструктор PHP Модификаторы доступа Наследование в PHP Константы класса PHP Подсказка типов PHP Подсказка интерфейсов Абстрактные классы PHP PHP Интерфейсы PHP Полиформизм PHP Трейты Статические методы PHP Статические свойства PHP Пространства имен PHP Итерируемые объекты

База данных MySQL

База данных MySQL Подключение к MySQL Создание БД MySQL Создание таблицы MySQL Вставка данных MySQL Получить ID MySQL Подготовленные операторы PHP MySQL Получение данных MySQL Предложение WHERE Предложение ORDER BY Обновление данных MySQL Удаление данных БД MySQL Limit Data

PHP XML

Парсеры PHP XML Парсер PHP SimpleXML Получить PHP SimpleXML PHP XML Expat PHP XML DOM

PHP - AJAX

AJAX Введение AJAX PHP AJAX База Данных AJAX XML AJAX Живой поиск AJAX Опрос

PHP Примеры

PHP Примеры Практика ООП PHP PHP квиз-тест Упражнения Базовый PHP Упражнения Алгоритмы Упражнения Массивы Упражнения Цикл for Упражнения Функции Регулярные выражения Упражнения Дата PHP Упражнения Строки PHP Математика PHP Упражнения Формы PHP Упражнения Классы PHP Упражнения JSON PHP PHP Задачник


Исключения (exceptions) PHP




В этом уроке вы узнаете, как генерировать и перехватывать исключения (exceptions) в PHP.


Как и в других языках, PHP имеет механизм исключений для обработки пользовательских ошибок. Исключение — это сигнал, указывающий на то, что что-то в процессе отличается от предполагаемого хода событий. Исключения могут быть вызваны различными причинами, обычно в случае ошибки, которые проявляются или могут быть специально созданы программой. В большинстве случаев подобные ситуации требуют выполнения специальных инструкций, чтобы предотвратить неконтролируемое завершение процесса.

Многие функции и классы PHP создают исключения.

Пользовательские функции и классы также могут вызывать исключения.

Исключения могут быть брошены throw и пойманы catch. Если исключение брошено, значит произошло что-то выходящее за рамки нормального течения процесса работы сценария, и необходимо выполнение какой-то другой функции. Подхват исключения происходит в специальной функции, которая сообщает остальной программе о том, что она готова обработать исключение.

Функция try-catch может самостоятельно выполнить необходимые действия или перебросить исключение другой функции.

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

Здесь важно отметить, что если мы выбрасываем исключение, но не определили блок catch, который должен обрабатывать это исключение, это приведет к фатальной ошибке. Поэтому важно убедиться, что мы определили блок catch, если бросаем исключения в своем приложении.

Если исключение не обнаружено, произойдет фатальная ошибка с сообщением "Uncaught Exception" (Неперехваченное исключение).

Попробуем сгенерировать исключение, не улавливая его:

<?php
function divide($dividend, $divisor) {
  // Выбросить исключение, если делитель равен нулю
  if($divisor == 0) {
    throw new Exception("Деление на ноль");
  }
  return $dividend / $divisor;
}

echo divide(5, 0);
?>

Результат выполнения кода:

Fatal error: Uncaught Exception: Деление на ноль in C:\webfolder\test.php:4 Stack trace: #0 C:\webfolder\test.php(14): divide(5, 0) #1 {main} thrown in C:\webfolder\test.php on line 9

Исключение генерируется оператором throw new Exception(), а ловится операторами try и catch.

Чтобы избежать ошибки из приведенного выше примера, мы можем использовать оператор try...catch для перехвата исключений и продолжения процесса.

Синтаксис

try {
  код, который может бросать (throw) исключения
} catch(Исключение $e) {
  код, который запускается при обнаружении исключения
}

При подходе, основанном на исключениях, программный код записывается в блоке try, исключение может быть создано с помощью оператора throw, когда во время выполнения кода в блоке try происходит исключительное событие. Затем он вылавливается и разрешается одним или несколькими блоками catch.

В следующем примере покажем сообщение при возникновении исключения:

<?php
function divide($dividend, $divisor) {
  if($divisor == 0) {
    throw new Exception("Деление на ноль");
  }
  return $dividend / $divisor;
}

try {
  echo divide(5, 0);
} catch(Exception $e) {
  echo "Невозможно разделить!";
}
?>

Когда исключение попадает в блок catch, объект Exception содержит сообщение об ошибке, которое было выбрано с использованием ключевого слова throw. Переменная $e, в приведенном выше примере, является экземпляром класса Exception, поэтому она имеет доступ ко всем методам этого класса. В этом блоке мы должны определить свою собственную логику обработки исключений — что именно мы хотим сделать с ошибкой, которую вы поймаете.

Иногда возникает необходимость выполнить часть кода независимо от того, было ли вызвано исключение в блоке try. Вот где мы можем использовать блок finally, поскольку код, который мы размещаем в блоке finally, всегда будет выполняться после выполнения блоков try и catch независимо от того, было ли выбрано исключение.

Важно понять, что catch выполнится в любом случае перед выходом из конструкции try...catch...finally, то есть эта особенность пригодится для обработки ситуаций, когда блок catch не отработал, а исключение возникло. Например, если блока catch нет вообще или в подобной ситуации, когда ожидается исключение определенного вида, а вызывается другое:

try { 
    echo "В try вызвано исключение\n";
    throw new StrangeException();
} catch (SomeException $e) {
    echo "Вызвано исключение SomeException \n";
} catch (AnotherException $e) {
    echo "Вызвано исключение AnotherException \n";
} finally {
    echo "Этот блок кода выполнится всегда\n";
}

В следующем примере покажем сообщение при возникновении исключения, а затем укажем, что процесс завершен:

<?php
function divide($dividend, $divisor) {
  if($divisor == 0) {
    throw new Exception("Деление на ноль");
  }
  return $dividend / $divisor;
}

try {
  echo divide(5, 0);
} catch(Exception $e) {
  echo "Невозможно разделить! ";
} finally {
  echo "Процесс завершен.";
}
?>

Результат выполнения кода:

Невозможно разделить! Процесс завершен.

В следующем примере смоделируем ситуацию, когда блока catch нет вообще, т.е. выведем строку "Процесс завершен", даже если исключение не было обнаружено:

<?php
function divide($dividend, $divisor) {
  if($divisor == 0) {
    throw new Exception("Деление на ноль");
  }
  return $dividend / $divisor;
}

try {
  echo divide(5, 0);
} finally {
  echo "Процесс завершен.";
}
?>

Объект Exception содержит информацию об ошибке или непредвиденном поведении, с которым столкнулась функция.

Синтаксис

new Exception(message, code, previous)

Параметры

Параметр Описание
message Необязательный. Строка, описывающая, почему было сгенерировано исключение.
code Необязательный. Целое число, которое можно использовать, чтобы легко отличить это исключение от других того же типа.
previous Необязательный. Если это исключение было сгенерировано в блоке catch другого исключения, рекомендуется передать это исключение в этот параметр.

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

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

Метод Описание
getMessage() Возвращает строку, описывающую, почему было создано исключение.
getPrevious() Если это исключение было вызвано другим, этот метод возвращает предыдущее исключение. Если нет, то возвращается null
getCode() Возвращает код исключения
getFile() Возвращает полный путь к файлу, в котором возникло исключение.
getLine() Возвращает номер строки кода, вызвавшего исключение.

Используем приведенные методы для для создания подробной информации о сгенерированном исключении:

<?php
function divide($dividend, $divisor) {
  if($divisor == 0) {
    throw new Exception("Деление на ноль", 1);
  }
  return $dividend / $divisor;
}

try {
  echo divide(5, 0);
} catch(Exception $ex) {
  $code = $ex->getCode();
  $message = $ex->getMessage();
  $file = $ex->getFile();
  $line = $ex->getLine();
  echo "Исключение добавлено в $file в строке $line: [Код $code]
  $message";
}
?>

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


Мы можем определить свои собственные обработчики исключений, чтобы по-своему обрабатывать различные типы исключений. Это позволяет нам использовать для каждого типа исключения отдельный блок catch.

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

<?php
// Расширение класса Exception
class EmptyEmailException extends Exception {}
class InvalidEmailException extends Exception {}
 
$email = "someuser@example..com";
 
try{
    // Выбрасывать исключение, если электронная почта пуста
    if($email == ""){
        throw new EmptyEmailException("

Пожалуйста, введите ваш E-mail адрес!

"); } // Выбрасывать исключение, если адрес электронной почты недействителен if(filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE) { throw new InvalidEmailException("

$email - это невалидный E-mail адрес!

"); } // Отобразить сообщение, если адрес электронной почты действителен echo "

SUCCESS: Email проверку прошел успешно

"; } catch(EmptyEmailException $e){ echo $e->getMessage(); } catch(InvalidEmailException $e){ echo $e->getMessage(); } ?>

В приведенном выше примере мы создали два новых класса исключений: EmptyEmailException и InvalidEmailException из базового класса Exception. Блоки catch используются для отображения различных сообщений об ошибках в зависимости от типа созданного исключения.

Созданные пользовательские классы исключений, как отмечалось выше, наследуют свойства и методы класса Exception, поэтому мы использовали методы класса Exception для получения информации об ошибке из объекта исключения.


Как уже отмечалось ранее, если исключение не перехвачено, PHP генерирует фатальную ошибку с сообщением "Uncaught Exception" (Неперехваченное исключение). Это сообщение об ошибке может содержать конфиденциальную информацию, такую ​​как имя файла и номер строки, в которой возникает проблема. Если, по какой-либо причине, вам необходимо срыть эту ​​информацию от пользователя, вы можете создать настраиваемую функцию и зарегистрировать ее в функции set_exception_handler() для обработки всех неперехваченных исключений.

<?php
function handleUncaughtException($e){
    // Отображение общего сообщения об ошибке для пользователя
    echo "Оппс! Что-то пошло не так. Повторите попытку или свяжитесь с нами, если проблема не исчезнет.";
    
    // Создадим строку ошибки
    $error = "Неперехваченное исключение: " . $message = date("Y-m-d H:i:s - ");
    $error .= $e->getMessage() . " в файле " . $e->getFile() . " на строке " . $e->getLine() . "\n";
    
    // Записать сведения об ошибке в файл
    error_log($error, 3, "var/log/exceptionLog.log");
}
 
// Зарегистрировать пользовательский обработчик исключений
set_exception_handler("handleUncaughtException");
 
// Бросить исключение
throw new Exception("Тестовое исключение!");
?>

Результат выполнения кода:

Оппс! Что-то пошло не так. Повторите попытку или свяжитесь с нами, если проблема не исчезнет.

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