Обработка исключений (Exception Handling) — это сигнал, указывающий на какое-то исключительное событие или ошибку. Исключения могут быть вызваны разными причинами, например, сбой подключения к базе данных или запроса, файл, к которому вы пытаетесь получить доступ, не существует и так далее.
PHP предоставляет мощный механизм обработки исключений, который позволяет их изящно обрабатывать. В отличие от традиционной системы обработки ошибок PHP, обработка исключений — это объектно-ориентированный подход к обработке ошибок, который обеспечивает более контролируемую и гибкую форму сообщения об ошибках. Модель исключений была впервые представлена в PHP 5.
Использование операторов Throw and Try…Catch
В подходе, основанном на исключениях, программный код записывается в блоке try
, исключение может быть создано с помощью оператора throw
, когда во время выполнения кода в блоке try
возникает исключительное событие. Затем он перехватывается и разрешается одним или несколькими блоками catch
.
В следующем примере показано, как работает обработка исключений:
<?php
function division($dividend, $divisor){
// Выбрасываем исключение, если делитель равен нулю
if($divisor == 0){
throw new Exception('Division by zero.');
} else{
$quotient = $dividend / $divisor;
echo "<p>$dividend / $divisor = $quotient</p>";
}
}
try{
division(10, 2);
division(30, -4);
division(15, 0);
// Если выбрано исключение, следующая строка не будет выполняться
echo '<p>All divisions performed successfully.</p>';
} catch(Exception $e){
// Обработка исключений
echo "<p>Caught exception: " . $e->getMessage() . "</p>";
}
// Продолжаем выполнение
echo "<p>Hello World!</p>";
?>
Система обработки исключений PHP состоит в основном из четырех частей: try
, throw
, catch
и класс Exception
. В следующем списке описывается, как именно работает каждая часть.
- Функция
division()
в приведенном выше примере проверяет, равен ли делитель нулю. Если это так, то с помощью оператораthrow
PHP генерируется исключение. В противном случае эта функция выполняет деление с использованием заданных чисел и отображает результат. - Позже в блоке
try
вызывается функцияdivision()
с разными аргументами. Если при выполнении кода в блокеtry
генерируется исключение, PHP останавливает выполнение в этой точке и пытается найти соответствующий блокcatch
. Если он найден, выполняется код в этом блокеcatch
, если нет, генерируется фатальная ошибка. - Блок
catch
обычно перехватывает исключение, созданное в блокеtry
, и создает объект ($e
), содержащий информацию об исключении. Сообщение об ошибке от этого объекта можно получить с помощью методаgetMessage()
.
PHP-класс Exception
также предоставляет методы getCode()
, getFile()
, getLine()
и getTraceAsString()
, которые можно использовать для генерации подробной отладочной информации.
<?php
// Отключаем отчет об ошибках по умолчанию
error_reporting(0);
try{
$file = "somefile.txt";
// Попытка открыть файл
$handle = fopen($file, "r");
if(!$handle){
throw new Exception("Cannot open the file!", 5);
}
// Попытка прочитать содержимое файла
$content = fread($handle, filesize($file));
if(!$content){
throw new Exception("Could not read file!", 10);
}
// Закрытие дескриптора файла
fclose($handle);
// Показываем содержимое файла
echo $content;
} catch(Exception $e){
echo "<h3>Caught Exception!</h3>";
echo "<p>Error message: " . $e->getMessage() . "</p>";
echo "<p>File: " . $e->getFile() . "</p>";
echo "<p>Line: " . $e->getLine() . "</p>";
echo "<p>Error code: " . $e->getCode() . "</p>";
echo "<p>Trace: " . $e->getTraceAsString() . "</p>";
}
?>
Конструктор Exception
дополнительно принимает сообщение об исключении и код исключения. Хотя сообщение об исключении обычно используется для отображения общей информации о том, что пошло не так, код исключения можно использовать для классификации ошибок. Предоставленный код исключения можно получить позже с помощью метода Exception
getCode()
.
Исключения следует использовать только для обозначения исключительных условий; они не должны использоваться для управления обычным потоком приложения, например, для перехода в другое место в скрипте в определенной точке. Это отрицательно скажется на производительности вашего приложения.
Определение пользовательских исключений
Вы даже можете определить свои собственные обработчики исключений, чтобы обрабатывать разные типы исключений по-разному. Это позволяет вам использовать отдельный блок catch
для каждого типа исключения.
Вы можете определить настраиваемое исключение, расширив класс Exception
, потому что Exception
является базовым классом для всех исключений. Пользовательский класс исключения наследует все свойства и методы от класса исключений PHP. Вы также можете добавить свои собственные методы в собственный класс исключений. Давайте посмотрим на следующий пример:
<?php
// Расширение класса Exception
class EmptyEmailException extends Exception {}
class InvalidEmailException extends Exception {}
$email = "someuser@example..com";
try{
// Проверяем, если адрес электронной почты пуст
if($email == ""){
throw new EmptyEmailException("<p>Please enter your E-mail address!</p>");
}
// Проверяем, если адрес электронной почты недействителен
if(filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE) {
throw new InvalidEmailException("<p><b>$email</b> is not a valid E-mail address!</p>");
}
// Отображаем сообщение об успешном завершении, если адрес электронной почты действителен
echo "<p>SUCCESS: Email validation successful.</p>";
} catch(EmptyEmailException $e){
echo $e->getMessage();
} catch(InvalidEmailException $e){
echo $e->getMessage();
}
?>
В приведенном выше примере мы создали два новых класса исключений: EmptyEmailException, и InvalidEmailException из базового класса Exception
. Несколько блоков catch
используются для отображения различных сообщений об ошибках в зависимости от типа сгенерированного исключения.
Поскольку эти настраиваемые классы исключений наследуют свойства и методы класса Exception
, мы можем использовать методы класса Exception
, такие как getMessage()
, getLine()
, getFile()
и т. д., для извлечения информации об ошибке из объекта исключения.
Установка глобального обработчика исключений
Как мы уже обсуждали ранее в этой главе, если исключение не перехвачено, PHP генерирует фатальную ошибку с сообщением Uncaught Exception …
. Это сообщение об ошибке может содержать конфиденциальную информацию, такую как имя файла и номер строки, в которой возникает проблема. Если вы не хотите предоставлять такую информацию пользователю, вы можете создать собственную функцию и зарегистрировать ее с помощью функции set_exception_handler()
для обработки всех неперехваченных исключений.
<?php
function handleUncaughtException($e){
// Отображаем общее сообщение об ошибке для пользователя
echo "Opps! Something went wrong. Please try again, or contact us if the problem persists.";
// Создаем строку ошибки
$error = "Uncaught Exception: " . $message = date("Y-m-d H:i:s - ");
$error .= $e->getMessage() . " in file " . $e->getFile() . " on line " . $e->getLine() . "\n";
// Записываем сведения об ошибке в файл
error_log($error, 3, "var/log/exceptionLog.log");
}
// Регистрируем пользовательский обработчик исключений
set_exception_handler("handleUncaughtException");
// Исключение
throw new Exception("Testing Exception!");
?>
Неперехваченное исключение всегда приводит к завершению работы скрипта. Поэтому, если вы хотите, чтобы скрипт продолжал выполняться после того, как произошло исключение, у вас должен быть хотя бы один соответствующий блок catch
для каждого блока try
.