Как мне обрабатывать ошибки в цепочках методов в Perl? - PullRequest
9 голосов
/ 15 августа 2011

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

Пример кода:

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

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

Ответы [ 3 ]

8 голосов
/ 15 августа 2011

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

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

use v5.12;

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

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

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

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

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

Это основная идея.Вы можете улучшить класс Null, чтобы он запомнил сообщение и место его создания, или добавить некоторые полиморфные методы (например, sub is_success { 0 }), чтобы он хорошо работал с интерфейсами объектов, которые вы ожидали получить.

Я думал, что где-то долго писал об этом, но сейчас не могу найти.

2 голосов
/ 15 августа 2011

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

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;
0 голосов
/ 15 августа 2011

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

...