#10.8 php Преобразование ошибок в исключения. Библиотека PHP_Exceptionizer. Иерархия уровней ошибок. Фильтрация по типам ошибок

Вспомним, что нефатальные ошибки типа E_WARNING, E_NOTICE и т.д., не нарушают нормальный ход работы программы, и возникновение их в программе приводит, максимум, к уведомлению в окне браузера или записи в лог-файл (если отслеживание соответствующего типа ошибки включено в конфигурационном файле php.ini).

Однако на практике появление даже такой "несерьёзной" с точки зрения PHP ошибки в программе может свидетельствовать о серьёзном нарушении хода программы с точки зрения её логики, которое, возможно, делает весь дальнейший код просто бессмысленным.

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

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

Другой подход заключается в автоматическом преобзовании перехватываемых ошибок в объекты исключений одноименных классов (E_WARNING, E_NOTICE и т.д.), и этот способ имеет следующие преимущества:

  • Объект-исключение содержит информацию о месте возникновения ошибки, а также стек вызовов функций, которые можно извлечь с помощью соответствующих методов класса Exception
  • Есть возможность по-разному обрабатывать различные типы ошибок (исключений):
      <?php
      try {
          //проверяемый код
      } catch (E_WARNING $e) {
          //код обработчика E_WARNING
      } catch (E_NOTICE $e) {
          //код обработчика E_NOTICE
      }
    
  • Можно преобразовывать в исключения не все типы ошибок, а только некоторые из них (например, только E_WARNING)
  • Классы-исключения объединены в иерархию наследования: при необходимости можно отлавливать ошибки не только того типа, который указан у параметра блока catch, но и наследуемые (более серьезные) типы ошибок

Код библиотеки PHP_Exceptionizer

<?php
class PHP_Exceptionizer 
{
    public function __construct($mask = E_ALL, $ignoreOther = false) 
    {
        $catcher = new PHP_Exceptionizer_Catcher();
        $catcher->mask = $mask;
        $catcher->ignoreOther = $ignoreOther;
        $catcher->prevHdl = set_error_handler(array($catcher, "handler"));
    }

    public function __destruct() 
    {
        restore_error_handler();
    }
}



class PHP_Exceptionizer_Catcher 
{
    public $mask = E_ALL;
    public $ignoreOther = false;
    public $prevHdl = null;

    public function handler($errno, $errstr, $errfile, $errline) 
    {
        if (!($errno & error_reporting())) return false;
        if (!($errno & $this->mask)) {
            if (!$this->ignoreOther) {
                if ($this->prevHdl) {
                    $args = func_get_args();
                    call_user_func_array($this->prevHdl, $args);
                } else {
                    return false;
                }
            }
            return true;
        }
        $types = array(
            "E_ERROR", "E_WARNING", "E_PARSE", "E_NOTICE", "E_CORE_ERROR",
            "E_CORE_WARNING", "E_COMPILE_ERROR", "E_COMPILE_WARNING",
            "E_USER_ERROR", "E_USER_WARNING", "E_USER_NOTICE", "E_STRICT", 
            "E_RECOVERABLE_ERROR", "E_DEPRECATED", "E_USER_DEPRECATED",
        );
        $className = "E_EXCEPTION";
        foreach ($types as $t) {
            $e = @constant($t);
            if ($errno & $e) {
                $className = $t;
                break;
            }
        }
        throw new $className($errno, $errstr, $errfile, $errline);
    }
}


abstract class PHP_Exceptionizer_Exception extends Exception 
{
    public function __construct($no = 0, $str = null, $file = null, $line = 0) 
    {
        parent::__construct($str, $no);
        $this->file = $file;
        $this->line = $line;
    }
}


class E_EXCEPTION extends PHP_Exceptionizer_Exception {}
class E_CORE_ERROR extends E_EXCEPTION {}
    class E_CORE_WARNING extends E_CORE_ERROR {}
    class E_COMPILE_ERROR extends E_CORE_ERROR {}
        class E_COMPILE_WARNING extends E_COMPILE_ERROR {}
    class E_ERROR extends E_CORE_ERROR {} 
        class E_RECOVERABLE_ERROR extends E_ERROR {} 
            class E_PARSE extends E_RECOVERABLE_ERROR {}
                class E_WARNING extends E_PARSE {}
                    class E_NOTICE extends E_WARNING {}
                        class E_STRICT extends E_NOTICE {}
                            class E_DEPRECATED extends E_STRICT {}
    class E_USER_ERROR extends E_ERROR {}
        class E_USER_WARNING extends E_USER_ERROR {}
            class E_USER_NOTICE extends E_USER_WARNING {}
                class E_USER_DEPRECATED extends E_USER_NOTICE {}