Захват нескольких типов исключений в одном блоке catch

Я хотел бы получить более чистый способ получить следующую функциональность, чтобы поймать AError и BError в одном блоке:

 try { /* something */ } catch( AError, BError $e ) { handler1( $e ) } catch( Exception $e ) { handler2( $e ) } 

Есть какой-либо способ сделать это? Или я должен поймать их отдельно?

AError и Berror есть общий базовый класс, но они также Berror его другим типам, которые я хотел бы handler2 , поэтому я не могу просто поймать базовый класс.

Если вы можете изменить исключения, используйте этот ответ .

Если вы не можете, вы можете попробовать поймать все с помощью Exception а затем проверить, какое исключение было выбрано с instanceof .

 try { /* something */ } catch( Exception $e ) { if ($e instanceof AError OR $e instanceof BError) { // It's either an A or B exception. } else { // Keep throwing it. throw $e; } } 

Но , вероятно, было бы лучше использовать несколько блоков catch, как описано в вышеупомянутом ответе .

 try { /* something */ } catch( AError $e ) { handler1( $e ); } catch ( BError $b ) { handler2( $e ); } 

Несмотря на то, что говорят эти другие ответы, вы можете поймать AError и BError в одном блоке (это несколько проще, если вы определяете исключения). Даже если у вас есть исключения, которые вы хотите «провалить», вы все равно сможете определить иерархию в соответствии с вашими потребностями.

 abstract class MyExceptions extends \Exception {} abstract class LetterError extends MyExceptions {} class AError extends LetterError {} class BError extends LetterError {} 

Затем:

 catch(LetterError $e){ //voodoo } 

Как вы можете видеть здесь и здесь , даже исключения по умолчанию для SPL имеют иерархию, которую вы можете использовать. Кроме того, как указано в руководстве PHP :

Когда генерируется исключение, код, следующий за оператором, не будет выполнен, а PHP попытается найти первый соответствующий блок catch.

Это означает, что вы также можете

 class CError extends LetterError {} 

которые вам нужно обрабатывать иначе, чем AError или BError , поэтому ваша инструкция catch будет выглядеть так:

 catch(CError $e){ //voodoo } catch(LetterError $e){ //voodoo } 

Если бы у вас был случай, когда было двадцать или более исключений, которые законно принадлежали под одним и тем же суперклассом, и вам нужно было обрабатывать пять (или любую другую группу с большими ионами) одного из них, а остальное – другого, вы можете это сделать.

 interface Group1 {} class AError extends LetterError implements Group1 {} class BError extends LetterError implements Group1 {} 

А потом:

 catch (Group1 $e) {} 

Использование OOP, когда дело доходит до исключений, очень сильно. Использование таких вещей, как get_class или instanceof – это хаки, и их следует избегать, если это возможно.

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

Вы могли бы

 function handleExceptionMethod1(Exception $e) { //voodoo } function handleExceptionMethod2(Exception $e) { //voodoo } 

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

 try { stuff() } catch(ExceptionA $e) { $this->handleExceptionMethod1($e); } catch(ExceptionB $e) { $this->handleExceptionMethod1($e); } catch(ExceptionC $e) { $this->handleExceptionMethod1($e); } catch(Exception $e) { $this->handleExceptionMethod2($e); } 

Таким образом, у вас все еще есть только одно местоположение кода, которое вы должны изменить, если ваш механизм обработки исключений должен измениться, и вы работаете в общих конструкциях ООП.

Приход в PHP 7.1 – это способность ловить несколько типов.

Чтобы это:

 <?php try { /* ... */ } catch (FirstException $ex) { $this->manageException($ex); } catch (SecondException $ex) { $this->manageException($ex); } ?> 

а также

 <?php try { } catch (FirstException | SecondException $ex) { $this->manageException($ex); } ?> 

функционально эквивалентны.

Начиная с PHP 7.1,

 catch( AError | BError $e ) { handler1( $e ) } 

интересно, вы также можете:

 catch( AError | BError $e ) { handler1( $e ) } catch (CError $e){ handler2($e); } catch(Exception $e){ handler3($e); } 

и в более ранних версиях PHP:

 catch(Exception $ex){ if($ex instanceof AError){ //handle a AError } elseif($ex instanceof BError){ //handle a BError } else { throw $ex;//an unknown exception occured, throw it further } } 

В этой статье рассматривается вопрос electrictoolbox.com/php-catch-multiple-exception-types . Содержание сообщения, скопированное непосредственно из статьи:

Примеры исключений

Вот некоторые примеры исключений, которые были определены для целей этого примера:

 class FooException extends Exception { public function __construct($message = null, $code = 0) { // do something } } class BarException extends Exception { public function __construct($message = null, $code = 0) { // do something } } class BazException extends Exception { public function __construct($message = null, $code = 0) { // do something } } 

Обработка нескольких исключений

Это очень просто – может быть блокировка для каждого типа исключений, которое может быть выбрано:

 try { // some code that might trigger a Foo/Bar/Baz/Exception } catch(FooException $e) { // we caught a foo exception } catch(BarException $e) { // we caught a bar exception } catch(BazException $e) { // we caught a baz exception } catch(Exception $e) { // we caught a normal exception // or an exception that wasn't handled by any of the above } 

Если выбрано исключение, которое не обрабатывается ни одним из других операторов catch, оно будет обрабатываться блоком catch (Exception $ e). Это необязательно должно быть последним.

В качестве дополнения к принятому ответу вы можете переключить тип исключения, в результате получившийся образец, который похож на исходный пример:

 try { // Try something } catch (Exception $e) { switch (get_class($e)) { case 'AError': case 'BError': // Handle A or B break; case 'CError': // Handle C break; case default: // Rethrow the Exception throw $e; } } 

Вот разумная альтернатива, если у вас нет контроля над определением исключений. Используйте имя переменной исключения для категоризации исключений, когда они пойманы. Затем проверьте переменную исключения после блока try / catch.

 $ABError = null; try { // something } catch (AError $ABError) { // let the exception fall through } catch (BError $ABError) { // let the exception fall through } catch (Exception $e) { handler2($e); } if ($ABError) { handler1($ABError); } 

Это несколько странно выглядящий подход, вероятно, стоит того, только если существует много дублирования между реализациями блоков catch.

Помимо провала, можно также перешагнуть с помощью goto . Это очень полезно, если вы хотите, чтобы мир горел.

 <?php class A_Error extends Exception {} class B_Error extends Exception {} class C_Error extends Exception {} try { throw new A_Error(); } catch (A_Error $e) { goto abc; } catch (B_Error $e) { goto abc; } catch (C_Error $e) { abc: var_dump(get_class($e)); echo "Gotta Catch 'Em All\n"; } 

3v4l.org

Отличный способ – использовать set_exception_handler .

Предупреждение!!! с PHP 7, вы можете получить белый экран смерти для фатальных ошибок. Например, если вы вызываете метод на не-объекте, вы обычно получаете Fatal error: Call to a member function your_method() on null и вы ожидаете увидеть это, если включена отчет об ошибках.

Вышеприведенная ошибка НЕ ​​будет поймана с помощью catch(Exception $e) . Вышеприведенная ошибка НЕ ​​запускает любой настраиваемый обработчик ошибок, заданный set_error_handler .

Вы должны использовать catch(Error $e){ } чтобы поймать ошибки в PHP7. , Это может помочь:

 class ErrorHandler{ public static function excep_handler($e) { print_r($e); } } set_exception_handler(array('ErrorHandler','excep_handler')); 

Другим вариантом, не указанным здесь, является использование атрибута code исключения, поэтому вы можете сделать что-то вроде этого:

 try { if (1 === $foo) { throw new Exception(sprintf('Invalid foo: %s', serialize($foo)), 1); } if (2 === $bar) { throw new Exception(sprintf('Invalid bar: %s', serialize($foo)), 2); } } catch (Exception $e) { switch ($e->getCode()) { case 1: // Special handling for case 1 break; case 2: // Special handling for case 2 break; default: // Special handling for all other cases } }