base16 10

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

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

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

Программисты, знакомые с такими языками структурного программирования, как C# и Java, по-видимому, давно привыкли использовать различные встроенные объекты, позволяющие справляться с ошибками и исключительными ситуациями. Таким специалистам будет приятно узнать, что теперь в версии PHP 5 впервые появился объект, предназначенный для обработки исключительных ситуаций, и что синтаксические конструкции для работы с этим объектом весьма напоминают существующие языки, такие как Java. В действительности даже после краткого знакомства с этими синтаксическими конструкциями разработчик может приступить к обработке ошибок и исключительных ситуаций в языке PHP во многом по такому же принципу, который применяется в других объектно-ориентированных языках.

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

Ошибки и исключительные ситуации

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

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

Ниже приведен пример кода, который содержит некоторые средства обнаружения ошибок в том виде, в каком они могло быть реализованы в версии PHP 4 или в одной из предыдущих версий. В этом коде осуществляется выборка переменной POST, содержащей идентификатор пользователя. Такой идентификатор должен иметь длину по меньшей мере девять символов и начинаться с префикса "usr":

Пример метода обработки ошибок без использования исключений
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Основы PHP</title>
</head>

<body>

<?php

// Выполнить выборку идентификатора пользователя, подлежащего проверке
$user_id = isset($_POST['user_id']) ? $_POST['user_id'] : '';

// Подготовить для вывода на дисплей сообщение, содержимое которого
// зависит от того, является ли действительным идентификатор пользователя
if (!empty($user_id))
	echo !is_valid_user($user_id) ? '<b style="color:red;">Некорректный логин</b><br>' : "Все правильно<br>";


function is_valid_user($user_id)
{	
	// Возвратить значение false, если идентификатор пользователя 
	// не начинается с подстроки "usr"
	$pre_str = "usr";
	if ((strpos($user_id, $pre_str) === false) || (strpos ($user_id, $pre_str) != 0))
		return false;
		
	// Возвратить значение false, если идентификатор пользователя 
	// не соответствует требованиям по длине 
	if ((strlen($user_id) < 9)) return false;
	
	return true;
}

?>

<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post">
    <input type="text" name="user_id" placeholder="Введите логин"><br>
    <input type="submit" value="Отправить">
</form>

</body>
</html>

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

Класс Exception

В версии PHP 5 предусмотрен новый класс Exception, который может непосредственно использоваться в любом коде, выполняемом под управлением сервера PHP 5 или более поздней версии. В примере, приведенном выше, применялись булевы функции, а класс Exception позволяет создавать или активизировать в коде исключительные ситуации — экземпляры этого класса.

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

Код PHP
<?php

// Выполнить выборку идентификатора пользователя, подлежащего проверке
$user_id = isset($_POST['user_id']) ? $_POST['user_id'] : '';

// Подготовить для вывода на дисплей сообщение, содержимое которого
// зависит от того, является ли действительным идентификатор пользователя
try
{
	if (!empty($user_id) && is_valid_user($user_id))
		echo "Все правильно<br>";
}
catch (Exception $ex)
{
	$msg = $ex->getMessage();
	echo $msg;
}


function is_valid_user($user_id)
{	
	// Активизировать исключение, если идентификатор пользователя 
	// не начинается с подстроки "usr"
	$pre_str = "usr";
	if ((strpos($user_id, $pre_str) === false) || (strpos ($user_id, $pre_str) != 0))
		throw new Exception('<b style="color:red;">Некорректный логин - должен начинаться со строки "usr"</b><br>');
		
	// Активизировать исключение, если идентификатор пользователя 
	// не соответствует требованиям по длине 
	if ((strlen($user_id) < 9)) 
		throw new Exception('<b style="color:red;">Некорректный логин - длина меньше 9 символов</b><br>');
	
	return true;
}

?>
Использование исключений

В этом коде для активизации исключения применяется оператор throw. А сами средства обработки исключительных ситуаций в данном случае использовались для создания нового объекта Exception. Благодаря применению этих средств появляется возможность обрабатывать ошибки, нарушающие нормальный ход выполнения программы, как отдельные исключительные ситуации, поэтому ошибки больше не могут влиять на остальную часть приложения.

Перехват и обработка исключительных ситуаций осуществляется с помощью управляющей конструкции try/catch. Прежде всего необходимо включить любой код, выполнение которого может привести к возникновению ошибки или исключительной ситуации, в конструкцию try(). При активизации в этом коде любой исключительной ситуации выполнение блока try() прекращается; это означает, что оставшийся код в конструкции try() не выполняется. Затем блок catch() просматривается для поиска исключительной ситуации соответствующего типа, а обработка исключительной ситуации происходит с помощью кода, содержащегося в данном конкретном блоке catch. Благодаря такой организации работы может быть предусмотрен анализ различных условий с учетом типа активизированной исключительной ситуации, но не предпринимается безнадежная попытка справиться с какой-то общей, неконкретизированной ошибкой.

Активизация исключительной ситуации

Благодаря использованию исключительных ситуациях появляется еще одна удобная возможность — предоставлять пользователю настолько много (или настолько мало) информации об ошибке, насколько это целесообразно. В сочетании с объектом Exception допускается применение нескольких методов обработки исключительных ситуаций, которые могут использоваться для создания собственных сообщений об ошибках или организации правильных действий в сложившейся ситуации.

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

Код PHP
try
{
	if (!empty($user_id) && is_valid_user($user_id))
		echo "Все правильно<br>";
}
catch (Exception $ex)
{
	// Входная строка, переданная объекту 
	$msg = $ex->getMessage(); 
	
	// Определяемый пользователем код ошибки 
	$code = $ex->getCode();
	
	// Имя файла, при обработке которого была активизирована 
	// исключительная ситуация 
	$file = $ex->getFile();
	
	// Номер строки, при обработке которой возникла исключительная ситуация 
	$line = $ex->getLine();
	
	echo "Ошибка в коде $code: $msg Файл: $file, номер строки: $line<br><br>";
}
Получение дополнительной информации об исключении

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

Определение собственных подклассов Exception

Язык PHP позволяет также определять собственные классы, которые наследуют методы класса Exception. Это означает, что можно больше не ограничиваться использованием лишь функции getMessage() для получения информации о том, какой именно тип имеет возникшая ошибка. Подклассы могут быть определены так, как показано в следующем примере:

Код PHP
class CustomException extends Exception {
	public function __construct($message) {
		parent::__construct($message);
	}
}

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

Код PHP
<?php

// Определить специализированные классы исключений
class PrefixException extends Exception {
	public function __construct($message) {
		parent::__construct($message);
	}
}

class MaxLengthException extends Exception {
	public function __construct($message) {
		parent::__construct($message);
	}
}

// Выполнить выборку идентификатора пользователя, подлежащего проверке
$user_id = isset($_POST['user_id']) ? $_POST['user_id'] : '';

// Подготовить для вывода на дисплей сообщение, содержимое которого
// зависит от того, является ли действительным идентификатор пользователя
try
{
	if (!empty($user_id) && is_valid_user($user_id))
		echo "Все правильно<br>";
}
catch (PrefixException $ex)
{
	// Если префикс "usr" отсутствует, добавить его
	$user_id = "usr".$user_id;
	
	// Повторный вызов проверки
	try {
		if (is_valid_user($user_id))
			echo "Все правильно<br>";
	} catch (Exception $ex) { 
		echo $ex->getMessage();
	}
}
catch (MaxLengthException $ex)
{
	$msg = $ex->getMessage(); 
	echo $msg;
}


function is_valid_user($user_id)
{	
	// Активизировать исключение, если идентификатор пользователя 
	// не начинается с подстроки "usr"
	$pre_str = "usr";
	if ((strpos($user_id, $pre_str) === false) || (strpos ($user_id, $pre_str) != 0))
		throw new PrefixException('<b style="color:red;">Некорректный логин - должен начинаться со строки "usr"</b><br>');
		
	// Активизировать исключение, если идентификатор пользователя 
	// не соответствует требованиям по длине 
	if ((strlen($user_id) < 9)) 
		throw new MaxLengthException('<b style="color:red;">Некорректный логин - длина меньше 9 символов</b><br>');
	
	return true;
}

?>

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

Ограничения средств обработки исключений языка PHP

Объект Exception — новое средство, появившееся в версии PHP 5, поэтому этот объект, как таковой, все еще находится на самых ранних этапах разработки. Ко времени написания этих строк язык PHP не поддерживал использование таких конструкций, как finally() и throws(), предусмотренных в языке Java и других языках. Кроме того, в отличие от других языков на исключительные ситуации еще не отображаются ошибки, распознаваемые самим интерпретатором PHP (в том числе ошибки, сообщения о которых обычно появляются в клиентском браузере). Из-за этого, например, возникновение ошибки в операторе SQL, выполняемом в блоке try/catch, не приводит автоматически к активизации исключительной ситуации, которую можно было бы перехватить и заняться ее обработкой. Такие удобные функциональные средства, по всей вероятности, должны быть включены в одну из будущих версий PHP, поэтому для авторов имеет смысл упомянуть о них, а для читателей — следить за их появлением.

Cookie-файлы и сеансы
Нарушения в работе системы PHP

Комментарии (0)

Результаты поиска по запросу

Система Orphus