1. ホーム
  2. php

[解決済み】1つのキャッチブロックに複数の例外タイプをキャッチする

2022-03-31 14:01:24

質問

次のような機能を取得するための、よりすっきりした方法が欲しいです。 AErrorBError を1つのブロックにまとめています。

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

何か方法はないでしょうか?それとも、別々にキャッチしなければならないのでしょうか?

AErrorBerror はベースクラスを共有していますが、他の型とも共有しているので、それを使ってフォールスルーで handler2 ということで、ベースクラスだけをキャッチすることはできません。

どのように解決するのですか?

アップデートしてください。

PHP 7.1より、ご利用いただけます。

構文は以下の通りです。

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

Docs https://www.php.net/manual/en/language.exceptions.php#example-294

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

コミット https://github.com/php/php-src/commit/0aed2cc2a440e7be17552cc669d71fdd24d1204a


PHP7.1以前の場合。

他の回答がどうであろうと、あなたは AErrorBError を同じブロックに入れることができます(例外を定義するのがあなたであれば、多少は簡単です)。たとえ、あなたが"fall through"したい例外があるとしても、あなたのニーズにマッチする階層を定義することができるはずです。

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 は、最初にマッチするキャッチブロックを探そうとします。

つまり、以下のようなことも可能です。

class CError extends LetterError {}

とは異なる処理を行う必要があります。 AError または 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);
}

この方法では、例外処理のメカニズムを変更する必要がある場合、変更する必要があるのは単一のコードロケーションだけであり、OOPの一般的な構成の中で作業していることになります。