2011-05-10 26 views
3

假設我有一個模塊Bar,它是模塊Foo的子類包裝器。我想調用Bar的方法來模擬Foo的 - 甚至是致命的錯誤。到目前爲止,很容易;我只是打電話給SUPER方法。如何捕獲並重新拋出Perl中的錯誤?


sub stuff { 
    # Do stuff here 

    SUPER::stuff(@_); 

    # Do more stuff here 
} 

但是,讓我們假設我想抓住,記錄並重新拋出任何致命錯誤SUPER::stuff()產生。前兩步很容易:


sub stuff { 
    # Do stuff here 

    eval { 
     SUPER::stuff(@_); 
    }; 
    [email protected] and log("Naughty, naughty: [email protected]"); 

    # Do more stuff here 
} 

...但我不知道如何做最後一部分。如何重新拋出錯誤,使得主叫方無法區分Foo->stuff()的呼叫和Bar->stuff()的呼叫?我可以在日誌聲明後插入die [email protected],並期望它能做我想做的事情嗎?或者在這裏有細微差別可能會讓我陷入困境?

+5

避免使用檢查'$ @'eval'後',尤其是面向對象的代碼。參見['Try :: Tiny'](http://search.cpan.org/~doy/Try-Tiny-0.09/lib/Try/Tiny.pm#BACKGROUND) – mob 2011-05-10 20:16:38

+1

@mob:那很荒謬。 – tchrist 2011-05-11 23:10:12

+0

@tchrist,我同意,但我也看到'$ @'在生產代碼中出現'eval' bug後重置。 – 2011-05-12 14:50:02

回答

1

你提出的建議是有效的。 Perl沒有結構化異常,因此[email protected]中的數據是所有調用者都會得到的。

+1

但是'$ @'*可以保存一個對象,它可以給你提供結構化的異常。 – tchrist 2011-05-12 20:06:14

+0

@tchrist:但是如果我只是用'$ @'重新死去作爲我的論點,我是否會失去任何數據? (假設我將'$ @'存儲到另一個變量,所以它不會被別的東西覆蓋,等等。) – BlairHippo 2011-05-18 14:31:28

+0

好點的tchrist。我忘記了這一點。 – Dan 2011-05-31 02:46:09

4

在Perl中安全評估/捕獲/記錄/重新拋出的完整代碼可能有點冗長。

sub stuff { 
    # Do stuff here 

    local [email protected]; # don't reset [email protected] for our caller. 
    my $eval_ok = eval { # get the return from eval, it will be undef if the eval catches an error. 
     SUPER::stuff(@_); 
     1; # return 1 (true) if there are no errors caught. 
    }; 
    if (!$eval_ok) { # don't trust [email protected] it might have been reset as the eval unrolled. 
     my $error = [email protected] || 'unknown error'; # copy [email protected] incase write_log resets [email protected], or is later changed to cause it to reset [email protected] 
     write_log("Naughty, naughty: $error"); 
     die $error; # after all that we can rethrow our error. 
    } 

    # Do more stuff here 
} 

可以使用Try::Tiny sugested由暴民簡化:

sub stuff { 
    # Do stuff here 

    try { 
     SUPER::stuff(@_); 
    } catch { 
     my $error = $_; 
     write_log("Naughty, naughty: $error"); 
     die $error; 
    } 

    # Do more stuff here 
} 
相關問題