Существует ряд проблем с eval.
Clobbering $ @
Когда вы запускаете блок eval, и он успешно выполняется, $ @ будет очищено, что может привести к сбою ошибки, которая в данный момент обнаруживается.
Это вызывает действиена расстоянии, сбрасывая предыдущие ошибки, возможно, ваш вызывающий еще не обработал.
$ @ должен быть правильно локализован перед вызовом eval, чтобы избежать этой проблемы.
В частности, $ @ заточенв начале eval, что также делает невозможным захват предыдущей ошибки перед вашей смертью (например, при создании объектов исключений со стеками ошибок).
По этой причине попытка фактически установит $ @ к предыдущемузначение (до локализации) в начале блока eval.
Локализация $ @ молча маскирует ошибки
Внутри блока eval матрица ведет себя какнапример:
sub die {
$@ = $_[0];
return_undef_from_eval();
}
Это означает, что если вы были вежливы и локализованы $ @, вы не можете умереть в этой области, иначе ваша ошибка будет отклонена (вместо этого будет напечатано «Что-то не так»).
Обходной путь очень уродлив:
my $error = do {
local $@;
eval { ... };
$@;
};
...
die $error;
$ @ может быть неверным значением
Этот код неверен:
if ( $@ ) {
...
}
потому что из-за предыдущих предупреждений он мог быть не установлен.
$ @ также может быть перегруженным объектом ошибки, который оценивается как ложный, но это все равно вызывает проблемы.
Классический режим отказаis:
sub Object::DESTROY {
eval { ... }
}
eval {
my $obj = Object->new;
die "foo";
};
if ( $@ ) {
}
В этом случае, поскольку Object :: DESTROY не локализует $ @, но все еще использует eval, он установит $ @ в "".
Деструктор вызывается, когдастек разматывается, после того как die устанавливает $ @ в "foo at Foo.pm line 42 \ n", поэтому к моменту вычисления ($ @) он был очищен с помощью eval в деструкторе.
Обходной путь для этого еще более уродлив, чем предыдущие.Несмотря на то, что мы не можем сохранить значение $ @ из кода, который не локализуется, мы можем по крайней мере быть уверены, что eval был прерван из-за ошибки:
my $failed = not eval {
...
return 1;
};
Это потому, что evalпойманный кубик всегда будет возвращать ложное значение.