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



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



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


есть ли способ сделать это? Или мне придется ловить их отдельно?



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

609   11  

11 ответов:

в последних версиях PHP это возможно. Смотрите ответ ниже.


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

если вы не можете, вы можете попробовать поймать все с 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 );
}

обновление:

начиная с PHP 7.1, это доступно.

синтаксис:

try
{
    // Some code...
}
catch(AError | BError $e)
{
    // Handle exceptions
}
catch(Exception $e)
{
    // Handle the general case
}

https://wiki.php.net/rfc/multiple-catch

https://github.com/php/php-src/commit/0aed2cc2a440e7be17552cc669d71fdd24d1204a


для PHP до 7.1:

несмотря на то, что эти другие ответы сказать, вы можете поймать 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) {}

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

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

вы могли бы

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

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

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

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
  }
}

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

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

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.

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

<?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'));

другой вариант не указан здесь, чтобы использовать

ХМ, есть много решений, написанных для php версии ниже 7.1.

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

<?php
$ex = NULL
try {
    /* ... */
} catch (FirstException $ex) {
    // just do nothing here
} catch (SecondException $ex) {
    // just do nothing here
}
if ($ex !== NULL) {
    // handle those exceptions here!
}
?>

Comments

    Ничего не найдено.