하나의 catch 블록에서 여러 예외 유형 잡기


244

나는 캐치로, 다음과 같은 기능을 얻을 수있는 청소기 방법을 싶습니다 AErrorBError한 블록에 :

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

이것을 할 수있는 방법이 있습니까? 아니면 따로 잡아야합니까?

AErrorBerror공유 기본 클래스를 가지고,하지만 난을 통해 가을에하고 싶은 것을 그들은 또한 다른 유형과 공유 handler2난 그냥 기본 클래스를 잡을 수 있습니다.


7
이것을 부수적으로 추가하기 만하면됩니다 : RFC는 여러 예외를 포착하기 위해 제출되었습니다. 이 기능이 PHP 언어에 적용되는지 확인하십시오 ... wiki.php.net/rfc/multiple-catch
SimonSimCity

10
^이 기능은 PHP 7.1에서 구현되었습니다
Subin

답변:


353

최신 정보:

PHP 7.1부터 사용할 수 있습니다.

구문은 다음과 같습니다.

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

문서 : https://www.php.net/manual/en/language.exceptions.php#example-287

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

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


7.1 이전의 PHP :

이러한 다른 답변의 말에도 불구하고, 당신은 잡을 수 AErrorBError같은 블록에 (당신이 예외를 정의하는 하나의 경우는 다소 쉽다). "중단"하려는 예외가 있다고해도 필요에 맞게 계층을 정의 할 수 있어야합니다.

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

당신이 다르게 처리해야하는 AErrorBError, 당신의 catch 문은 다음과 같이 할 수 있도록 :

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

동일한 수퍼 클래스에 합법적으로 속한 20 개 이상의 예외가 있고 그 중 5 개 (또는 큰 그룹)를 한 가지 방법으로 처리해야하고 나머지는 다른 방법으로 처리해야하는 경우에도 여전히이를 수행 할 수 있습니다.

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

이러한 방식으로 예외 처리 메커니즘을 변경해야하는 경우 수정해야하는 유일한 단일 코드 위치가 있으며 일반적인 OOP 구성 내에서 작업하고 있습니다.


4
정답으로 이에 대한 또 다른 투표가 있습니다. 안타깝게도 받아 들여진 답변에서 언급 된 것과 정답으로 받아 들여진다는 사실은 PHP를 광기로 만드는 것입니다.
borfast

이것이 정답입니다. 그러나 파일을 수정할 수 있다고 가정합니다. AError타사에서 업데이트 한 라이브러리 / 파일에서 구현할 수 있습니다.
Kayla

@ WaffleStealer654 파일을 직접 편집 할 수없는 경우에도 파일을 서브 클래 싱하여 파일을 그룹화 할 수 있습니다. 그것은 예외를 던질 수 있다고 가정하지만 예외가 발생할 가장 기본적인 메커니즘을 감싸고 예외를 잡아서 던질 수 있습니다.
MirroredFate

3
타사 라이브러리를 사용할 때는 그렇게 할 수 없기 때문에이 답변은 허용되지 않습니다.
Denis V

@DenisV 당신의 위에 내 의견을 참조하십시오. 엔터프라이즈 소프트웨어에서 항상 수행됩니다. 캡슐화가 훌륭합니다.
MirroredFate

229

PHP> = 7.1에서는 이것이 가능합니다. 아래 답변을 참조하십시오 .


예외를 수정할 수 있으면 이 답변을 사용하십시오 .

당신이 할 수 없다면, 당신은 모두를 잡아서 시도 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 );
}

6
그것이 내가 두려워했던 것입니다. 함께 처리해야 할 오류 유형이 많으면 함께 잡기 및 유형을 테스트하는 것이 좋을 것입니다.하지만 제 경우와 같이 2 개만 따로 잡는 것이 더 깨끗합니다. 감사!
Dominic Gurto

3
@DominicGurto : 예, 저도 함께 갈 것입니다 :) 나는 finally진술에 대한 PHP의 태도에 더 관심이 있습니다 . ;)
alex

7
그러나 이것이 모든 예외를 포착한다는 것을 잊지 마십시오 ... } else { throw($e); }. 따라서 두 가지와 일치하지 않는 것이 있어야합니다 . 구문이 잘못되어 죄송합니다. 잠시 동안 PHP를 보지 못했습니다.
Dalibor Filus

11
php.net/manual/en/language.exceptions.php 에서 첫 번째 단락을 읽으면 여러 catch 블록이 가능하고 완벽하게 유효한 솔루션입니다. OP는 하나의 catch 문에 실수로 두 개의 예외 클래스를 넣었습니다. 여러 catch 블록이있는 다른 예제로 답변을 업데이트하는 것이 좋습니다.
Haralan Dobrev

4
당신의 다른 모든 예외를 먹는 해결책 제안, 전혀 받아 들여져서는 안됩니다 ...
Stivni

88

오는 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);
}
?>

기능적으로 동일합니다.


45

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

25

이 기사는 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) 블록에 의해 처리됩니다. 반드시 마지막 일 필요는 없습니다.


3
이 방법의 문제점은 둘 이상의 다른 예외에 대해 동일한 코드를 실행해야 할 때 발생합니다.
Parziphal

Electric Toolbox 에서 검색했습니다 . 크레딧을 제공하기 위해 게시물을 수정 중입니다.
Kayla

PHP 7.x에서는 catch (Throwable $e)모든 예외를 잡아야합니다. 참조 : php.net/manual/en/class.throwable.php
Mikko Rantalainen

21

허용 된 답변의 확장으로 Exception 유형을 전환하여 원래 예제와 다소 유사한 패턴을 만들 수 있습니다.

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;

    }

}

6
이 솔루션 대신 여러 캐치를 사용하십시오.
Alejandro Moreno

5

예외 정의를 제어 할 수없는 경우 합리적인 대안이 있습니다. 예외가 발생했을 때 예외를 분류하려면 예외 변수의 이름을 사용하십시오. 그런 다음 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);
}

캐치 블록 구현 사이에 중복이 많은 경우이 다소 이상하게 보이는 접근 방법은 그만한 가치가 있습니다.


3

폴 스루 외에도 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


1

좋은 방법은 사용하는 것 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'));

1
... 또는 당신은 그것을 작성 catch (Throwable $e) { ... }하고 끝낼 수 있습니다. 참조 : php.net/manual/en/class.throwable.php
Mikko Rantalainen

0

여기에 나열되지 않은 다른 옵션 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
    }
}

나는 공감하지 않았지만 아마도 OOP 순수 주의자들은 당신이 extends \Exception?
keyboardSmasher

알았다. 그것은 내 솔루션의 요점입니다. 특정 예외를 throw하기 위해 네임 스페이스를 설정하기 위해 임의의 클래스를 만들 필요가 없습니다. 그들이 코드를 지정하는 기능을 추가 한 이유는 확실합니다.
Mike Purcell

나는 downvote하지 않았지만 downvoters는 이것이 질문에 대답하지 않는다고 생각합니다. 나는 것을 독자에게 명확하게 뭔가 대답 시작하는 게 좋을 것 당신이 질문을 이해하고 당신은 여전히 코드 흐름에 대한 총 다른 방법을 제안하고자한다. 이 답변은 실제로 "다양한 예외 유형 을 잡는 방법 "이 아니라 "예외에 대한 여러 가지 다른 원인을 처리하는 방법 "에 대한 답변 입니다.
Mikko Rantalainen

0

흠, 7.1보다 낮은 PHP 버전을 위해 작성된 많은 솔루션이 있습니다.

다음은 모든 예외를 잡기를 원하지 않고 공통 인터페이스를 만들 수없는 사람들을위한 간단한 것입니다.

<?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!
}
?>
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.