如何处理Perl中方法链中的错误?

时间:2011-08-15 12:36:25

标签: perl error-handling catalyst dbix-class template-toolkit

处理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)中处理此类错误的更好方法,请建议。 一个实际的例子是当用户搜索某些内容时,这不存在。

3 个答案:

答案 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,允许方法链传播相同的错误。