1つのcatchブロックで複数の例外タイプをキャッチする


243

私はキャッチに、以下の機能を取得するためにクリーンな方法を希望AErrorし、BError1つのブロックに:

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

これを行う方法はありますか?それとも別々にキャッチする必要がありますか?

AErrorそして、Berror共有ベースクラスを持っていますが、私はにフォールスルーしたいことを、彼らはまた、他のタイプとそれを共有しhandler2、私はちょうど基本クラスをキャッチすることはできませんので、。


7
補足としてこれを追加するだけです:複数の例外をキャッチするためのRFCが提出されました。この機能がPHP言語に組み込まれるかどうかを見てみましょう... wiki.php.net/rfc/multiple-catch
SimonSimCity

10
^この機能はPHP 7.1で実装されています
Subin

回答:


351

更新:

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の場合:

これらの他の回答が言うことにもかかわらず、あなたがキャッチすることができますAErrorし、BError同じブロック内で(あなたが例外を定義する1であれば、それはいくらか容易です)。「フォールスルー」したい例外があるとしても、ニーズに合わせて階層を定義できるはずです。

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

AErrororとBErrorは異なる方法で処理する必要があるため、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);
}

このようにして、例外処理メカニズムを変更する必要がある場合でも、変更する必要があるコードの場所は1つだけであり、OOPの一般的な構造内で作業しています。


4
これが正解としての別の投票です。残念ながら、受け入れられた回答で述べられていることや、それが正解として受け入れられていることなどが、PHPを狂気にしているのです。
ボーファスト2014

これは受け入れられる答えになるはずです。ただし、ファイルを変更できることを前提としています。AErrorサードパーティによって更新されるライブラリ/ファイルに実装できます。
Kayla 14

@ WaffleStealer654ファイルを直接編集できない場合でも、ファイルをサブクラス化してグループに実装させることができます。これは、例外をスローできると想定しますが、例外がスローされる最も基本的なメカニズムをラップし、それをキャッチして、ラップされた例外をスローすることもできます。
MirroredFate 2014

3
サードパーティのライブラリを使用している場合はこれを行うことができないため、これは受け入れられない回答です。
Denis V

@DenisVあなたの上の私のコメントを見てください。それは常にエンタープライズソフトウェアで行われます。カプセル化は素晴らしいです。
MirroredFate 2014

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つだけの場合、個別にキャッチする方がおそらくクリーンです。ありがとう!
ドミニクグルト2011

3
@DominicGurto:ええ、私もそれで行きます:)私はfinallyステートメントに対するPHPの態度にもっと関心があります。;)
alex

7
しかし、これがすべての例外をキャッチすることを忘れないでください。そのため... } else { throw($e); }、2つが一致しないようなものがあるはずです。構文が間違っている可能性があるため申し訳ありませんが、しばらくの間PHPが表示されませんでした。
Dalibor Filus、2011

11
ここで最初の段落を読むと、php.net / manual / en / language.exceptions.php複数のcatchブロックが可能であり、完全に有効なソリューションであることがわかります。OPは誤って2つの例外クラスを1つのcatchステートメントに入れていました。複数のcatchブロックを使用した別の例で回答を更新する方が良いと思います。
Haralan Dobrev 2013

4
他のすべての例外を
食い止める

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

複数の例外の処理

これは非常に簡単です。スローできる例外タイプごとにキャッチブロックが存在する可能性があります。

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
このメソッドの問題は、2つ以上の異なる例外に対して同じコードを実行する必要がある場合に発生します。
Parziphal 2013年

これはElectric Toolboxから取得されました。クレジットを付与するために投稿を編集しています。
Kayla 14

PHP 7.xでは、catch (Throwable $e)すべての例外をキャッチする必要があります。参照:php.net/manual/en/class.throwable.php
Mikko Rantalainen

21

受け入れられた回答の拡張として、例外のタイプを切り替えて、元の例のようなパターンを作成できます。

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
このソリューションの代わりに複数のキャッチを使用します。
アレハンドロモレノ

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

このやや奇妙に見えるアプローチは、catchブロックの実装間で多くの重複がある場合にのみ、おそらく価値があります。


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
ミッコランタライネン2018年

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

とった。これが私のソリューションの要点です。特定の例外をスローするために名前空間を確立するためだけに、任意のクラスを作成する必要はありません。彼らがコードを指定する機能を追加した理由は確かです。
Mike Purcell

私も反対票を投じなかったが、反対投票者はこれが質問に答えないことを信じていると思う。読者が質問を理解し、コードフローのまったく異なる方法を提案すること読者に明らかにするようなものから、回答を始めることをお勧めします。この回答は、実際には「複数の例外タイプをキャッチする方法」ではなく、「例外の複数の異なる原因を処理する方法」には回答していません。
ミッコランタライネン2018年

0

うーん、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!
}
?>
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.