处理Perl链接方法中的异常的最佳方法是什么? 如果链接的任何方法抛出异常
,我想分配值0或undef代码示例:
my $x = $obj->get_obj->get_other_obj->get_another_obj->do_something;
最好的办法是什么? 我每次都必须在try / catch / finally语句中包装吗? 我想要应用的上下文是:我正在使用Catalyst和DBIC进行Web开发,我做了很多链式结果集,如果这个结果集中的一些抛出异常,我只想分配0或undef的值,然后对待它模板中的错误(我使用Template Toolkit)。如果还有另一种方法可以做到这一点而不包含try / catch中的每个调用,请告诉我。如果您知道在相同的上下文(Catalyst / DBIC / TT)中处理此类错误的更好方法,请建议。 一个实际的例子是当用户搜索某些内容时,这不存在。
答案 0 :(得分:8)
我通过在失败点返回一个空对象来处理这个问题。该对象通过简单地返回自身来响应每个方法,因此它一直这样做,直到它吃掉剩余的方法。最后,您查看$x
以查看它是您期望的结果还是此null对象。
以下是这样一个例子:
use v5.12;
package Null {
my $null = bless {}, __PACKAGE__;
sub AUTOLOAD { $null }
}
对于每个被调用的方法,AUTOLOAD都会拦截它并返回空对象。
当您遇到错误时,将返回其中一个Null对象。在方法链的中间你仍然得到一个对象,所以当你调用下一个方法时Perl不会爆炸。
sub get_other_obj {
...;
return Null->new if $error;
...;
}
在链的末尾,您可以查看您返回的内容,看它是否为Null对象。如果这就是你所得到的,那就发生了一件坏事。
这是基本的想法。您可以改进Null类以使其记住消息及其创建位置,或者添加一些多态方法(例如sub is_success { 0 }
)以使其与您期望获得的对象的接口很好地匹配。 / p>
我以为我已经在某处写了很长时间,但现在我找不到了。
答案 1 :(得分:2)
您可以编写一个标量方法,将方法链包装在错误处理中:
my $try = sub {
@_ > 1 or return bless {ok => $_[0]} => 'Try';
my ($self, $method) = splice @_, 0, 2;
my $ret;
eval {
$ret = $self->$method(@_);
1} or return bless {error => $@} => 'Try';
bless {ok => $ret} => 'Try'
};
{package Try;
use overload fallback => 1, '""' => sub {$_[0]{ok}};
sub AUTOLOAD {
my ($method) = our $AUTOLOAD =~ /([^:]+)$/;
$_[0]{ok} ? $_[0]{ok}->$try($method, @_[1..$#_]) : $_[0]
}
sub DESTROY {}
sub error {$_[0]{error}}
}
使用它:
{package Obj;
sub new {bless [0]}
sub set {$_[0][0] = $_[1]; $_[0]}
sub add {$_[0][0] += ($_[1] || 1); $_[0]}
sub show {print "Obj: $_[0][0]\n"}
sub dies {die "an error occured"}
}
my $obj = Obj->new;
say "ok 1" if $obj->$try(set => 5)->add->add->show; # prints "Obj 7"
# and "ok 1"
say "ok 2" if $obj->$try('dies')->add->add->show; # prints nothing
say $obj->$try('dies')->add->add->show->error; # prints "an error occured..."
$try
方法的第一行还允许使用以下语法:
say "ok 3" if $obj->$try->set(5)->add->add->show;
答案 2 :(得分:-1)
一个想法是创建一个类,当在string / number / boolean上下文中计算实例对象时,使用overload
返回false值,但仍然允许在其上调用方法。 AUTOLOAD
方法始终可以返回$self
,允许方法链传播相同的错误。