Исключения — это новые и важные компоненты РНР5, представляющие универсальный механизм расширяемой, удобной для обслуживания и объектно-ориентированной обработки ошибок.
Основная идея обработки ошибок состоит в выполнении кода внутри так называемого блока try. Этот блок представляет собой раздел кода следующего вида:
try
{
//здесь находится необходимый код
}
В случае возникновения непредвиденных ситуаций внутри блока try можно выполнить так называемую генерацию исключения. В РНР исключения нужно генерировать вручную. Это выполняется следующим образом:
throw new Exception ('сообщение ', код);
Ключевое слово throw включает механизм обработки исключения. Приведенный фрагмент скорее представляет собой конструкцию языка, а не функцию, но ему необходимо передать значение. Эта конструкция ожидает получения объекта. В простейшем случае ее можно использовать для создания экземпляра встроенного класса Exception, как и было сделано в приведенном примере.
Конструктор этого класса принимает два параметра: сообщение и код. Они служат для представления сообщения об ошибке и номера ошибки. Оба эти параметра необязательны.
И наконец, за блоком try должен следовать как минимум один блок catch, который выглядит подобно показанному ниже:
catch (указание_типа исключения)
{
// обработка исключения
}
Объект, передаваемый в блок catch (и перехватываемый им), является тем, который передается (и генерируется) оператором throw, генерирующим исключение. Исключение может быть любого типа, однако удобнее всего использовать либо класс Еxception, либо экземпляры собственных пользовательских исключений, унаследованных от класса Еxception.
В случае возникновения исключения код РНР ищет соответствующий блок catch. При наличии более одного блока catch передаваемые в них объекты должны иметь различные типы, чтобы РНР мог определить, какой именно блок catch соответствует конкретному случаю.
Еще один заслуживающий внимания момент связан с возможностью генерирования дополнительных исключений внутри блока catch.
Рассмотрим простой пример обработки исключений:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<?php
try
{
throw new Exception ('Возникла очень серьезная ошибка', 42);
}
catch (Exception $e)
{
echo 'Исключение '. $e -> getCode(). ': '. $e -> getMessage() . ' в ' . $e -> getFile(). ', строка '. $e ->getLine(). '<br>';
}
?>
Результат выполнения кода показан ниже на рисунке.
Из листинга видно, что мы воспользовались несколькими методами класса Exception, которые будут рассмотрены позже. В приведенном примере кода было сгенерировано исключение класса Exception. Методы этого встроенного класса можно использовать в блоке catch для вывода полезного сообщения об ошибке.
PHP5 поставляется со встроенным классом Exception. Как уже упоминалось, конструктор этого класса принимает два параметра: сообщение об ошибке и номер ошибки.
Кроме конструктора, этот класс содержит следующие встроенные методы:
Как видите, в коде листинга были использованы четыре из этих методов. Эту ж еинформацию (плюс информацию отслеживания) можно было бы получить с помощью оператора:
echo $e;
Информация отслеживания указывает, какие функции выполнялись в момент возникновения исключения.
Вместо создания и передачи экземпляра базового класса Exception можно передавать любой другой объект. В большинстве случаев вы будете расширять класс Exception для создания своих собственных классов и исключений.
Конструкция throw позволяет передавать любые другие объекты. иногда такая потребность может возникнуть при наличии проблем, связанных с каким-то конкретным объектом, и необходимости его передачи в целях отладки.
Как уже говорилось, в большинстве случаев приходится расширять базовый класс Exception. В руководстве по РНР показан код, который демонстрирует основу класса Exception.
Класс Exception — компоненты класса, которые можно наследовать
<?php
class Exception {
function __construct (string $message = NULL, int $code = 0)
{
if (func_num_args())
{
$this -> message = $message;
}
$this -> code = $code;
$this -> file = __FILE__;//из конструкции throw
$this -> line = __LINE__;//из конструкции throw
$this -> trace = debug_backtrace();
$this -> string = StringFormat($this);
}
protected $message = 'Unknown exception';//сообщение исключения
protected $code = 0; //определяемый пользователем код исключений
protected $file; // исходное имя файла
protected $line; //исходная строка исключения
private $trace; //информация отслеживания
private $string; //только для внутреннего пользования!!
final function getMessage()
{
return $this -> message;
}
final function getCode()
{
return $this -> code;
}
final function getFile()
{
return $this -> file;
}
final function getTrace()
{
return $this -> trace;
}
final function getTraceAsString()
{
return self::TraceFormat($this);
}
function __toString()
{
return $this -> string;
}
static private function StringFormat(Exception $exception)
{
//... недоступная в РНР-сценариях функция,
//которая возвращает всю необходимую информацию в виде строки
}
static private function TraceFormat(Exception $exception)
{
// ... недоступная в РНР-сценариях функция,
//которая возвращает всю информацию отслеживания в виде строки
}
}
?>
Основная причина, по которой было приведено определение класса, состоит в том, что большинство общедоступных методов являются финальными: то есть, их нельзя перекрыть. Можно создать собственный субкласс Exceptions, но нельзя менять поведение базовых методов. Вместе с тем, можно перекрывать функцию __toString(), чтобы изменить способ отображения исключения. Можно также добавлять собственные методы.
Пример определенного пользователем класса Exception user_defined_exception.php
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<?php
class myException extends Exception
{
function __toString()
{
return '<table border><tr><td><strong>Исключение '. $this -> getCode(). '</strong>: '.$this -> getMessage(). '<br>'.'в '
.$this-> getFile(). ', строка '. $this-> getLine()
.'</td></tr></table><br>';
}
}
try
{
throw new myException('Произошла очень серьезная ошибка ', 42);
}
catch (myException $m)
{
echo $m;
}
?>
Результат выполнения кода показан на рисунке.
В этом коде объявляется новый класс исключения с именем myException, расширяющий класс Exception. Различие между этим классом и классом Exception связано с заменой метода __toString() для обеспечения более "изящного" вывода сообщения об исключении.
Приведенный пример очень прост, Далее мы рассмотрим способы создания различных исключений, связанных с различными категориями ошибок.
Похожие материалы по теме:
Подсчет объектов или статических членов и методов. Обработка исключительных ситуаций