Исключения в PHP

Модель исключений (exceptions) в PHP 5 проще, чем в других языках программирования. Исключение можно сгенерировать (как говорят, «выбросить») при помощи оператора throw, и можно перехватить (или, как говорят, «поймать») оператором catch. Код выбрасывающий исключение, должен быть окружен блоком try, для того чтобы можно было перехватить исключение. Каждый блок try должен иметь как минимум один соответствующий блок catch. Так же можно использовать несколько блоков catch, перехватывающих различные классы исключений. Нормальное выполнение (когда не генерируется исключений в блоках try или когда класс выброшенного исключения не совпадает с классами, объявленными в соответствующих блоках catch) будет продолжено за последним блоком catch. Исключения так же могут быть сгенерированны (или перегерерированы — т.е. выброшены снова) оператором throw внутри блока catch.

При генерации исключения, код следующий ниже оператора throw исполнен не будет, а PHP предпримет попытку найти первый блок catch, перехватывающий исключение данного класса. Если исключение не будет перехвачено, PHP выдаст сообщение об ошибке: «Uncaught Exception …» (Неперехваченное исключение), если конечно не был определен обработчик ошибок при помощи функции set_exception_handler().

Пример #1 Выброс исключений

<?php
function inverse($x) {
    if (!$x) {
        throw new Exception('Деление на ноль.');
    }
    else return 1/$x;
}

try {
    echo inverse(5) . "\n";
    echo inverse(0) . "\n";
} catch (Exception $e) {
    echo 'Выброшено исключение: ',  $e->getMessage(), "\n";
}

// Продолжение выполнения
echo 'Hello World';
?>

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

0.2
Выброшено исключение: Деление на ноль.
Hello World

НАСЛЕДОВАНИЕ ИСКЛЮЧЕНИЙ
Определенный пользователем класс исключения должен быть определен, как класс расширяющий (наследующий) встроенный класс Exception. Ниже приведены методы и свойства класса Exception, доступные дочерним классам.
Пример #2 Встроеный класс Exception

<?php
class Exception
{
    protected $message = 'Unknown exception';   // сообшение
    protected $code = 0;                        // Код исключения,
    определяемый пользователем
    protected $file;                            // файл в котором было
    выброшено исключение
    protected $line;                            // строка в которой было
    выброшено исключение

    function __construct($message = null, $code = 0);

    final function getMessage();                // Возвращает сообшение
    исключения 
    final function getCode();                   // Код исключения
    final function getFile();                   // Файл, где выброшено
    исключение
    final function getLine();                   // Строка, выбросившая исключени
    final function getTrace();                  // Массив backtrace()
    final function getTraceAsString();          // Обратная трассировка как
    строка

    /* Overrideable - т.е. то, что можно переопределить */
    function __toString();                       // должен вернуть
    форматированную строку, для отображения
}
?>

Если класс, наследуемый от Exception переопределяет конструктор, необходимо вызвать в конструкторе parent::__construct(), чтобы быть уверенным, что все дынные будут доступны. Метод __toString() может быть переопределен, что бы обеспечить нужный вывод, когда объект преобразуется в строку.

Пример #3 Наследование класса Exception

<?php
/**
 * Определим свой класс исключения
 */
class MyException extends Exception
{
    // Переопределим исключение так, что параметр message станет обязательным
    public function __construct($message, $code = 0) {
        // какой-то код 
    
        parent::__construct($message, $code);
    }

    // Переопределим строковое представление объекта.
    public function __toString() {
        return __CLASS__ . ": [{$this->code}]: {$this->message}\n";
    }

    public function customFunction() {
        echo "Мы можем определять новые методы в наследуемом классе\n";
    }
}


/**
 * Создадим класс для тестирования исключения
 */
class TestException
{
    public $var;

    const THROW_NONE    = 0;
    const THROW_CUSTOM  = 1;
    const THROW_DEFAULT = 2;

    function __construct($avalue = self::THROW_NONE) {

        switch ($avalue) {
            case self::THROW_CUSTOM:
                // Бросаем собственное исключение
                throw new MyException('1 - неправильный параметр', 5);
                break;

            case self::THROW_DEFAULT:
                // Бросаем встроеное исключение
                throw new Exception('2 - недопустимый параметр', 6);
                break;

            default: 
                // Никаких исключений, объект будет создан.
                $this->var = $avalue;
                break;
        }
    }
}


// Example 1
try {
    $o = new TestException(TestException::THROW_CUSTOM);
} catch (MyException $e) {      // Will be caught
    echo "Поймано собственное, переопределенное исключение\n", $e;
    $e->customFunction();
} catch (Exception $e) {        // Будет пропущено.
    echo "Поймано встроенное исключение\n", $e;
}

// Отсюда будет продолжено выполнение программы
var_dump($o);
echo "\n\n";


// Example 2
try {
    $o = new TestException(TestException::THROW_DEFAULT);
} catch (MyException $e) {      // Тип исключения не совпадет
    echo "Поймано переопределенное исключение\n", $e;
    $e->customFunction();
} catch (Exception $e) {        // Будет перехвачено
    echo "Перехвачено встроенное исключение\n", $e;
}

// Отсюда будет продолжено выполнение программы
var_dump($o);
echo "\n\n";


// Example 3
try {
    $o = new TestException(TestException::THROW_CUSTOM);
} catch (Exception $e) {        // Будет перехвачено.
    echo "Поймано встроенное исключение\n", $e;
}

// Продолжение исполнения программы
var_dump($o);
echo "\n\n";


// Example 4
try {
    $o = new TestException();
} catch (Exception $e) {        // Будет пропущено, т.к. исключение не выкидывается
    echo "Поймано встроенное исключение\n", $e;
}

// Продолжение выполнения программы
var_dump($o);
echo "\n\n";
?>
Реклама

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход /  Изменить )

Google photo

Для комментария используется ваша учётная запись Google. Выход /  Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход /  Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход /  Изменить )

Connecting to %s