Перехват собственных исключений

6 мар. 2014 г., 19:40:18
Просмотры: 13.6K
Голосов: 3

Я создаю пакет с собственными исключениями, но при попытке перехватить исключение получаю фатальную ошибку: Uncaught exception. Эта ситуация возникает только когда метод с исключением вызывается через add_action( 'init', array( $this, 'wp_some_method' ) ); Пример:

class SomeClass {
    public function __construct() {
        add_action( 'init', array( $this, 'wp_some_method' ) );
        echo '__constructor<br />';
    }
    function some_method(){
        throw new \Exception('сообщение об ошибке');
    }
    function wp_some_method( $post_type ){
        throw new \Exception('Вторая ошибка'); 
    }
}
try{
    echo 'try <br />';
    $o = new SomeClass();
    //$o->some_method(); - здесь исключение перехватывается правильно

} catch (\Exception $ex) {
    echo $ex->getMessage();
}

На экране отображается:

try

__constructor

И затем: Fatal error: Uncaught exception 'Exception'

2
Комментарии

Когда выбрасывается исключение, класс уже создан, а блок try уже выполнился и завершился. Лучший способ продемонстрировать это — добавить комментарий после оператора try catch, который говорит //the init hook has not been fired yet

Tom J Nowell Tom J Nowell
6 мар. 2014 г. 20:03:34

Я отредактировал свой пост. Но я не понимаю ваш ответ.

Michał Kalkowski Michał Kalkowski
6 мар. 2014 г. 21:52:27
Все ответы на вопрос 1
0

Ваше исключение не перехватывается блоком try{} catch(){}, потому что оно не выбрасывается внутри этого блока. Это демонстрирует непонимание асинхронных событий и системы хуков/действий/событий WordPress.

Методы вашего объекта прикреплены к хуку действия init и выбрасываются при срабатывании хука init, а не при создании объекта и не при их прикреплении.

Например:

class SomeClass {
    public function __construct() {
        // когда происходит действие/событие init, вызывается метод wp_some_method
        add_action( 'init', array( $this, 'wp_some_method' ) );
    }
    function wp_some_method( $post_type ){
        throw new \Exception('ошибка'); 
    }
}
try{
    // отлично, исключения не было при создании объекта
    $o = new SomeClass();    
} catch (\Exception $ex) {
    echo $ex->getMessage();
}

// спустя некоторое время где-то в ядре WordPress...

do_action( 'init' ); // метод, который мы прикрепили к хуку init, выбросил исключение, но не было ничего, чтобы его перехватить!

Ваш метод не вызывается при создании объекта. Он прикреплен к событию init, но не вызывается, именно потому что событие 'init' еще не произошло. Событие init происходит значительно позже выполнения вашего блока try{} catch.

Вместо этого более подходящими будут следующие варианты:

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

В противном случае нет рациональной, логической или здравой причины, по которой строка кода с throw new \Exception должна выполняться внутри блока try catch, как у вас выше, без вашего явного вызова вручную, как вы это сделали в тесте.

6 мар. 2014 г. 22:37:50