AError
とBError
を1つのブロックにまとめるために、次の機能を取得するためのよりクリーンな方法が欲しいです。
try
{
/* something */
}
catch( AError, BError $e )
{
handler1( $e )
}
catch( Exception $e )
{
handler2( $e )
}
これを行う方法はありますか?それとも別々に捕まえる必要がありますか?
AError
とBerror
は共有基本クラスを持っていますが、それらは私がhandler2
にフォールオーバーしたい他の型ともそれを共有しているので、基本クラスをキャッチすることはできません。
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 );
}
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
これらの他の答えが言うことにもかかわらず、あなたは同じブロックの中でAError
とBError
を捕らえることができます(例外を定義している方がやや簡単です)。たとえあなたが「通過する」ことを望む例外があるとしても、あなたはまだあなたのニーズに合うように階層を定義することができるはずです。
abstract class MyExceptions extends Exception {}
abstract class LetterError extends MyExceptions {}
class AError extends LetterError {}
class BError extends LetterError {}
その後:
catch(LetterError $e){
//voodoo
}
お分かりのように、 here および here を見てください。デフォルトのSPL
例外でさえ、利用できる階層を持っています。さらに PHP Manual に書いてあるように:
例外が投げられると、ステートメントに続くコードは実行されず、PHPは最初にマッチしたcatchブロックを見つけようとします
これはまたあなたが持つことができることを意味します
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);
}
このようにして、例外処理メカニズムを変更する必要がある場合でも、変更する必要があるコードの場所は1つだけであり、OOPの一般的な構成内で作業しています。
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ブロックの実装間に多くの重複がある場合にのみおそらく価値があります。
フォールスルーの他に、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";
}
良い方法はset_exception_handler
を使うことです。
警告!!! PHP 7を指定すると、致命的なエラーのために白い画面が表示されることがあります。たとえば、非オブジェクトに対してメソッドを呼び出すと、通常はFatal error: Call to a member function your_method() on null
が返され、エラー報告が有効になっていればこれが表示されるはずです。
上記のエラーはcatch(Exception $e)
で捉えられません。上記のエラーはset_error_handler
で設定されたカスタムエラーハンドラをトリガーしません。
PHP7でエラーを検出するにはcatch(Error $e){ }
を使わなければなりません。 。これは役に立ちます。
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
}
}
うーん、7.1より低いバージョンのphp用に書かれた多くの解決策があります。
これは、すべての例外をキャッチする必要がなく、一般的なインターフェイスを作成できない場合のための、もう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!
}
?>