В модели ООП при возникновении ошибки создается и генерируется (throw) исключение. Это означает, что при генерировании исключения во время выполнения сценария оно будет постоянно передаваться в стек вызовов до тех пор, пока не произойдет одно из следующих событий:
Исключение будет перехвачено одной из функций в стеке.
Исключение не будет перехвачено и достигнет вершины стека.
Генерирование исключения в сценарии осуществляется с помощью оператора throw и передачи ему экземпляра генерируемого исключения, как показано в листинге 13.26.
Листинг 13.26. Генерирование исключения
<? php
class ThrowExample {
public function makeError() {
throw new Exception("Пример исключения");
}
}
$inst = new ThrowExample();
$inst->makeError();
?>
В листинге 13.26 во время выполнения метода makeError() генерируется исключение, передаваемое в стек вызовов, который в данном случае является одноуровневым
стеком. Поскольку для перехвата этого исключения нет соответствующей логики, возникнет ошибка и произойдет останов сценария:
Fatal error : Uncaught exception 'exception' with message 'This is an example Exception' in /listing_13_26.php:4
Неисправимая ошибка: Неперехваченное исключение 'exception' с сообщением
'Пример исключения' в /listing_13_26.php:4
Stack trace:
#0 /listing_13_26.php(8): ThrowExample->makeError()
#1 {main}
318
thrown in /listing_13_26.php on line 4
Как видите, исключения формируют гораздо более информативные сообщения об ошибках, чем доступные в версии PHP 4. Однако даже с учетом такой степени информативности лучше всего исправлять ошибки незаметно для пользователя. Чтобы сделать это с помощью исключений, используйте новую конструкцию PHP 5 — блок try/catch.
Блок try/catch служит для выполнения сегмента кода, который может генерировать исключение и вернуться к выполнению кода. Синтаксис блока try/catch выглядит следующим образом:
try {
/* код для выполнения */
}
catch (ExceptionClass $variable) {
/* Код для перехвата исключения */
}
[ catch (AnotherException $variable) {
} ] ...
Обратите внимание, что ExceptionClass и $variable — это просто заполнители. На
самом деле ExceptionClass может быть выражен любым классом, унаследованным от
класса Exception . Если в PHP-сценарии используется блок try/catch , будут выполнены
следующие действия:
1. Выполняется код в части try блока .
2. Если в блоке try не было обнаружено ни одного исключения, выполнение сценария продолжается за пределами блока try.
3. Если возникло исключение, класс исключения сравнивается с исключениями, которые были перехвачены в блоке try.
4. Если блок try перехватывает сгенерированное исключение, выполняется код в блоке catch, в котором была перехвачена ошибка.
5. Если блок try не перехватывает исключение, оно помещается в стек вызовов.
При перехвате исключения сгенерированный объект исключения присваивается переменной, имя которой указано в блоке перехвата (в предыдущем синтаксисе — переменная $variable).
В завершение анализа исключений рассмотрим код в листинге 13.27, основанный на примере из листинга 13.26.
Листинг 13.27. Перехват исключений в PHP 5
<?php
class MyException extends Exception {
/* Никакого другого нового кода не нужно,
просто новый тип исключения */
}
class AnotherException extends Exception {
/* Класс оболочки для определения другого
типа исключения */
}
class ThrowExample {
public function makeMyException() {
throw new MyException();
}
public function makeAnotherException() {
throw new AnotherException();
}
public function makeError() {
throw new Exception();
}
}
$inst = new ThrowExample();
try {
$inst->makeMyException();
} catch(MyException $e) {
echo "Перехвачено 'MyException'\n";
}
try {
$inst->makeAnotherException();
} catch(MyException $e) {
echo "Перехвачено 'MyException'\n";
} catch(AnotherException $e) {
echo "Caught 'AnotherException'\n";
}
try {
$inst->makeError();
}
catch(MyException $e) {
echo "Перехвачено 'MyException'\n";
} catch(AnotherException $e) {
echo "Перехвачено 'AnotherException'\n";
}
Несмотря на большой объем кода, в листинге 13.27 представлено несколько примеров использования блоков try/catch вместе с исключениями. В этом примере создан простой класс ThrowExample, который генерирует три разновидности класса Exception: собственно класс Exception, класс MyException и класс AnotherException. Затем создается экземпляр класса ThrowExample и генерируются все три исключения, используя три отдельных блока try/catch. При выполнении этого сценария выполняется код в блоке try, генерирующий исключение с типом MyException. Поскольку это исключение перехватывается в блоке try вызова функции, выполняется код в блоке catch. Во втором блоке try процесс повторяется, но на этот раз генерируется исключение AnotherException.
В этом случае определены два типа исключений, которые будут перехватываться, поэтому оба исключения сравниваются со сгенерированным исключением. Так как блок try действительно перехватывает исключение AnotherException, то выполняется его блок catch . Для третьего блока try генерируется исключение, которое не перехватывается ни одним из блоков catch. Хотя класс Exception является родительским классом по отношению к классам MyException и AnotherException, он не является таким же специфическим классом, поэтому соответствие не может быть установлено и исключение передается в сценарий, что приводит к возникновению ошибки, останавливающей выполнение сценария. Если выполнить код из листинга 13.27, будет сгенерирован следующий вывод:
Перехвачено 'MyException'
Перехвачено 'AnotherException'
Fatal error: Uncaught exception 'exception' in /exp.php:18
Stack trace:
#0 /exp.php(39): ThrowExample->makeError()
#1 {main}
thrown in /exp.php on line 18
Как и можно было предположить, первые два исключения перехватываются соответствующими блоками try, и выполнение сценария продолжается. Однако выполнение
сценария прекращается после вызова метода makeError(), поскольку при этом генерируется исключение, которое нельзя перехватить.
Исключения подчиняются иерархии объектов, как и любой другой класс в PHP. Следовательно, вы можете перехватить любое сгенерированное исключение с помощью следующего блока try/catch:
try {
/* Некоторый код */
} catch (Exception $e) {
/* Вызывается при генерировании исключения */
}
Поскольку все исключения наследуют внутренний класс Exception в PHP, то перехват самого класса Exception в результате приведет к перехвату любого генерируемого исключения.
Исключения являются невероятно мощным инструментом для программиста, использующего объектно-ориентированную модель. Однако использовать их необходимо
всегда очень осторожно! Не следует полагаться на исключения как на способ управления выполнен