Exception :: Class对象应该在布尔上下文中求值为false

时间:2015-09-21 08:49:25

标签: perl

我第一次尝试Exception :: Class,让我感到惊讶的是,从函数返回时Exception :: Class对象的计算结果为true。不应该默认是相反的。

我知道我可以通过超载来改变它,但我想知道这是不是一个好主意

sub gethtml{
    return MyException->new( error => 'some error' );
}
my $response = &gethtml  

if($response){
    #do something with the html 
}
else{
    #something went wrong check if it's an exception object
}

2 个答案:

答案 0 :(得分:3)

您将异常与返回错误值以表示错误相混淆。

例外的一部分是它们提供了自己的通道来指示错误。这使return空闲,只返回有效值。无需检查错误与已定义或特殊对象,或者根本不进行任何按功能调用错误检查。这一切都在街区尽头被捕获和处理。

如果你返回一个异常对象,它就会失败;它们不是例外,它们只是错误代码。

要利用异常,示例中的代码应如下所示:

sub get_html {
    ...try to get the html...

    return $html if defined $html;

    MyException->throw( error => 'some error' );
}

eval { 
    my $html = get_html;
    # do something with $html;
}
if ( my $e = Exception::Class->caught() ) {
    ...deal with the error...
}

使用Try::Tiny可以使这更漂亮。

当你必须做很多可能出错的事情时,这会更有意义,例如一堆文件,网络或数据库操作。查看autodiePath::Tiny等模块,了解其工作原理。

答案 1 :(得分:2)

您不应该使用new创建一个并将其返回。他们有一个throw方法,可以自动充当构造函数和die

use strict;
use warnings;
use Exception::Class qw( InputException HTTPException );
use Try::Tiny;

sub get_html {
  my ($url) = @_;

  # input validation
  InputException->throw(error => 'no URL') unless $url;

  my $res = $ua->get($url);
  if ($res->is_success) {
    # do more stuff with $res;
  } else {
    HTTPException->throw( error => 'request failed' );      
  }  
}

# ... later

my $url;
try {
  get_html($url);
} catch {
  # handle the error which is in $_
  if ( $_->isa('InputException') ) {
    print "You need to supply a URL";
  } elsif ( $_->isa('HTTPException') ) {
    print "Could not fetch the HTML because the HTTP request failed.\n";
    print "But I am not telling you why.";
  }
}

然后你可以去catch他们(使用Try::Tiny)或者只是将它包装在一个eval中。但基本上这些例外是简单的对象。它们的目的是作为die的返回值并被抛出,因此无需将它们返回到任何地方。

一旦程序死掉,调用堆栈上的所有作用域都会被强行退出,直到你最终进入eval块(catch为止)。在那里,你可以处理错误。而且由于该错误是一个对象,你可以用它做一些奇特的东西。

+--------------------------------------------------------------------+          
| sub {                                                              |          
| +----------------------------------------------------------------+ |          
| | if () {                                                        | |          
| | +------------------------------------------------------------+ | |          
| | | foo:: sub {                                                | | |          
| | | +--------------------------------------------------------+ | | |          
| | | | catch {                                                | | | |          
| | | | +----------------------------------------------------+ | | | |          
| | | | | doo_stuff:: sub {                                  | | | | |          
| | | | | +------------------------------------------------+ | | | | |          
| | | | | |                                                | | | | | |          
| | | | | | MyException->throw ==> die $obj  +---------------------------------+
| | | | | | do_more_stuff(); # never executed              | | | | | |         |
| | | | | |                                                | | | | | |         |
| | | | | +------------------------------------------------+ | | | | |         |
| | | | +----------------------------------------------------+ | | | |         |
| | | |                                                        | | | |         |
| | | | handle_exception_in_catch($_)        <---------------------------------+
| | | | # ( in Try::Tiny the exception ends up in $_ )         | | | |          
| | | |                                                        | | | |          
| | | +--------------------------------------------------------+ | | |          
| | +------------------------------------------------------------+ | |          
| +----------------------------------------------------------------+ |          
+--------------------------------------------------------------------+          

另请参阅Exception::Class文档。

如果您混合例外情况以及常规dieCarp croak来电,则在使用->isa之前,您必须检查是否有人受到祝福。 Safe::Isa在这里派上用场。

use strict;
use warnings;
use Exception::Class qw( InputException HTTPException );
use Try::Tiny;
use Safe::Isa;

sub get_html {
  my ($url) = @_;

  # input validation
  InputException->throw(error => 'no URL') unless $url;

  my $res = $ua->get($url);
  if ($res->is_success) {
    # do more stuff with $res;
    die "There is no answer in this HTML" if $res->decoded_content !~ m/42/;
  } else {
    HTTPException->throw( error => 'request failed' );      
  }  
}

使用此代码,$_->isa('...')会爆炸,因为die调用时,$_不是对象,您无法调用方法isa未经证实的参考(或非参考)。 Safe :: Isa提供了$_isa,它首先检查它,否则只返回false

my $url;
try {
  get_html($url);
} catch {
  # handle the error which is in $_
  if ( $_->$_isa('InputException') ) {
    print "You need to supply a URL";
  } elsif ( $_->$_isa('HTTPException') ) {
    print "Could not fetch the HTML because the HTTP request failed.\n";
    print "But I am not telling you why.";
  }
}

有关其工作原理的详细信息,请参阅mst's talk You did what?