2011-12-09 57 views
152

我想一個更清潔的方式來獲得以下功能,捕捉AErrorBError在一個塊:捕獲多種異常

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

有沒有辦法做到這一點?或者我必須分別抓住他們?

AErrorBerror有一個共享的基類,但他們也與我想要通過其他類型分享到handler2,所以我不能只抓住基類。

+6

只是爲了添加爲一個側面說明:RFC已被提交以捕獲多個異常。讓我們來看看這個特性是否能夠進入PHP語言...... https://wiki.php.net/rfc/multiple-catch – SimonSimCity

+6

^這個特性已經在PHP 7.1中實現了 – Subin

回答

177

如果您可以修改例外,use this answer

如果你不能,你可以嘗試使用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; 
    } 
} 

它可能會是更好的use multiple catch blocks as described in aforementioned answer

try 
{ 
    /* something */ 
} 
catch(AError $e) 
{ 
    handler1($e); 
} 
catch (BError $b) 
{ 
    handler2($e); 
} 
+5

這就是我所害怕的。如果需要一起處理多種錯誤類型,將它們捕捉到一起並測試類型會很好,但是對於只有2種錯誤類型(如我的情況),單獨捕獲它們可能更乾淨。謝謝! –

+3

@DominicGurto:是的,我也會這麼做:)我會更關心PHP對'finally'語句的態度。 ;) – alex

+7

但是不要忘記,這會捕獲所有的異常,所以應該有'...} else {throw($ e); }'如果它不符合這兩個。對不起,也許錯誤的語法,沒有看到一段時間的PHP。 –

19

進行了擴展,接受的答案,你可以切換導致,有點像原來的例子的圖案異常的類型:

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; 

    } 

} 
+5

使用多個捕獲而不是此解決方案。 –

23

本文介紹的問題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

+0

這是從[電動工具箱](http://www.electrictoolbox.com/php-catch-multiple-exception-types/)檢索到的。編輯帖子給信貸。 – Kayla

+0

對於PHP 7.x,您需要catch(Throwable $ e)來捕獲所有異常。另見:http://php.net/manual/en/class.throwable.php –

153

儘管這些其他答案說,你可以在同一個塊中捕獲AErrorBError(如果你是定義例外的那個,它會更容易一些)。即使考慮到有些例外,你仍然應該能夠定義一個等級來滿足你的需求。

abstract class MyExceptions extends \Exception {} 

abstract class LetterError extends MyExceptions {} 

class AError extends LetterError {} 

class BError extends LetterError {} 

然後:

catch(LetterError $e){ 
    //voodoo 
} 

正如你可以看到herehere,甚至SPL默認的異常都有可以利用的層次結構。此外,作爲PHP Manual說:

當一個異常被拋出,代碼後面的語句將不被執行 和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_classinstanceof之類的東西都是黑客行爲,應儘可能避免。

我想補充的另一個解決方案是將異常處理功能放入其自己的方法中。

你可以有

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的一般結構中工作,那麼您仍然只有一個代碼位置需要修改。

+17

這是做這件事的正確方法 –

+6

這應該是被接受的答案。 – Raisch

+4

下面是對此的另一個投票,作爲正確的答案。不幸的是,像被接受的答案中所說的那樣,以及它被接受爲正確答案的事實,使得PHP變得瘋狂。 – borfast

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塊實現之間有很多重複時才值得。

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

也許你勇敢的下決心解釋一下嗎? –

+0

我沒有downvote,但也許OOP純粹主義者很生氣,你沒有使用'extends \ Exception'創建新的異常類? – keyboardSmasher

+0

明白了。這就是我的解決方案的重點,你不需要創建任意類來建立一個命名空間來拋出一個特定的異常。我確定這就是爲什麼他們添加了指定代碼的能力。 –

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')); 
+0

......或者你可以只寫'catch(Throwable $ e){...}'並完成它。另見:http://php.net/manual/en/class.throwable.php –

3

除了落空,它也可以通過使用轉到步驟了。 如果你想看到世界燃燒,這是非常有用的。

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

82

即將在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); 
} 
?> 

在功能上等同。

36

由於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 
    } 
} 
+2

Upvoted用於解釋更老的和更新的PHP版本 – crafter