Бросить исключение в следующий блок Catch

Я хочу перехватить пользовательское исключение, выполнить некоторую логику с ним, и, если оно потерпит неудачу, выбросить его в более общий блок catch. Вот так:

class My_Exception extends Exception {
protected $_nonFatal = false;

public function __construct($value, $nonFatal = false) {
$this->_nonFatal = (bool)$nonFatal;

return parent::__construct($value);
}

public function isNonFatal() {
return (bool)$this->_nonFatal;
}
}

try {

} catch (My_Exception $e) {
if ($e->isNonFatal) {
// #1
// Err gently
}

// #2
// The error was fatal, so keep throwing it
throw new Exception($e->getMessage());

} catch (Exception $e) {
// #3
echo 'An exception was caught with the message '.$e->getMessage();
}

Так что я ловлю My_Exceptionпроверьте, не является ли это нефатальной ошибкой. Если это так, ошибочно, (раздел № 1). Если нет (раздел № 2), я хочу, чтобы был запущен второй улов (раздел № 3). Вместо этого throw new Exception в разделе № 2 выходит try/catch/catch все вместе.

Я мог бы использовать оператор switch в классе $e но я думаю, что это грязнее Есть ли стандартный способ сделать это, что мне не хватает?

1

Решение

Если нет (раздел № 2), я хочу, чтобы был запущен второй улов

Блоки try / catch работают не так — блок catch всегда будет выходить из блока try / catch; он не «проваливается», как операторы switch.

Вам нужно обернуть свой код другим блоком try / catch.

try {
try {
// ...
} catch (My_Exception $e) {
if ($e->isNonFatal) {
// #1
// Err gently
}

// #2
// The error was fatal, so keep throwing it
throw new Exception($e->getMessage());
}
} catch (Exception $e) {
// #3
echo 'An exception was caught with the message '.$e->getMessage();
}

Есть ли стандартный способ сделать это, что мне не хватает?

Там нет реального «стандартного» способа сделать это либо; обычно вы не обобщаете исключение с другим исключением, но если приложение корректно, то именно так вы и захотите это сделать.

Лучший способ управлять цепочкой исключений — это передать ваше пользовательское исключение предыдущее исключение в конструкторе. Таким образом, есть вероятность, что любой, кто поднимет исключение, может использовать Exception.getPrevious()и отобразите свое исключение вместе с более общим.

2

Другие решения

К сожалению, блоки catch не могут позаботиться о каком-либо исключении, которое выдается внутри предыдущего блока catch, даже если оно было вызвано другим вызовом функции.
Другими словами, любое необработанное исключение, выброшенное изнутри блока catch #1 не будет виден изнутри блока № 2 (но вместо этого будет обрабатываться четным верхним блоком catch в стеке вызовов):

try {
error_prone_code();
} catch (My_Exception $e) { // #1
throw new \Exception($e->getMessage());
} catch (Exception $e) { // #2
echo "Something bad happend: {$e->getMessage()}";
}

затем, честно говоря, сразу вложенные блоки try / catch выглядят довольно некрасиво.
Если логика вашего приложения не слишком сложна, вы можете сохранить свой код в чистоте и порядке, используя экземпляр оператор.

try {
error_prone_code();
// Make sure to catch the standard Exception base class
} catch (\Exception $e) {
// instanceof operator tells if object:
// is an instance of a specific class
// is an instance of some class that extends the mentionned class
// 's class implements a specific interface
if ( ! $e instanceof My_Exception || ! $e->isNonFatal() ) {
echo "Fatal exception arose: {$e->getMessage()}";
// You may also throw the same exception to some catch block upper in the call stack.
// throw $e;
} else {
// Gentle handling
}
}
1

По вопросам рекламы [email protected]