Как обрабатывать ошибки в цепочках методов в Perl?

каков наилучший способ справиться с исключениями, брошенными в цепочку методов в Perl? Я хочу назначить значение 0 или undef, если какой-либо из методов прикован к исключению

код:

my $x = $obj->get_obj->get_other_obj->get_another_obj->do_something;

какой лучший способ сделать это? Должен ли я каждый раз оборачивать оператор try/catch/finally? Контекст, который я хочу применить, это: Im работает в веб-разработке с использованием Catalyst и DBIC, и я делаю много цепных наборов результатов, и если некоторые из этих наборов результатов бросают исключение я просто хочу назначить значение 0 или undef, а затем обработать эту ошибку в шаблоне (Im с помощью Template Toolkit). Если есть другой способ сделать это, не оборачивая каждый вызов в try / catch, пожалуйста, дайте мне знать. Если вы знаете лучший способ лечения этого типа ошибок в том же контексте (Catalyst/DBIC/TT), пожалуйста, предложите. Практическим примером может быть, когда пользователь ищет что-то, и этого не существует.

3 ответов


я обрабатываю это, возвращая нулевой объект в момент сбоя. Этот объект реагирует на каждый метод, просто возвращая себя, поэтому он продолжает делать это, пока не съест остальные методы. В конце вы смотрите в $x чтобы увидеть, является ли это результатом, который вы ожидали, или этот нулевой объект.

вот пример такой вещи:

use v5.12;

package Null {
    my $null = bless {}, __PACKAGE__;
    sub AUTOLOAD { $null }
    }

для каждого вызываемого метода автоматическая загрузка перехватывает его и возвращает пустой объект.

когда вы бежите в ошибка, вы возвращаете один из этих объектов Null. В середине цепочки методов вы все равно получаете объект обратно, поэтому Perl не взрывается при вызове следующего метода.

sub get_other_obj {
    ...;
    return Null->new if $error;
    ...;
    }

в конце цепочки вы можете проверить, что у вас есть, чтобы увидеть, является ли это нулевым объектом. Если это то, что у тебя есть, то случилось что-то плохое.


вы можете написать скалярный метод, который обернет цепочку методов при обработке ошибок:

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;

можно было бы создать класс, который использует overload чтобы вернуть значение false, когда объект экземпляра оценивается в контекстах string/number/boolean, но все равно позволяет вызывать методы. Ан AUTOLOAD метод всегда может вернуться $self позволяя цепочке методов распространять ту же ошибку.