Как обрабатывать ошибки в цепочках методов в 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
позволяя цепочке методов распространять ту же ошибку.