[Moscow.pm] $SIG{__DIE__} и require/use
Nikita Zubkov
nikzubkov на gmail.com
Пн Авг 8 07:06:24 PDT 2011
Всем привет.
В своих проектах использую объекты исключений для отслеживания места
их возникновения и прочих вкусных штук. Я использую не
Exception::Class в связи с некоторыми специфическими потребностями, но
проблема касается так же и Exception::Class.
Реализуется все примерно следующим кодом:
my $base_class = '...'; # базовый класс исключения
my $error_class = '...'; # класс исключения-ошибки
sub rethrow {
my $e = @_ ? $_[0] : $@;
die $e
if blessed( $e ) && $e->isa( $base_class );
die $error_class->new( $e );
}
sub try(&) {
my $code = $_[0];
eval {
local $SIG{__DIE__} = \&rethrow;
&$code();
};
$@;
}
При создании объекта исключения собирается стэк вызовов.
Используется это все примерно так:
my $e = try {
# тут потенциально падающий код
};
# показываем расширенную информацию об ошибке
show_error( $e ) if $e;
Все работает отлично, кроме одного случая. Если внутри try я попытаюсь
загрузить модуль, во время загрузки которого происходит ошибка или
вызывается исключение, то обработчик $SIG{__DIE__} вызывается 2 раза и
во-второй раз на входе у него не первоначально созданный объект
исключения, а его "стрингифицированный" вариант (+ дополнительная
информация от компилятора) и в контексте второго вызова уже другое
состояние стэка (без первоначального места возникновения исключения).
Это вызывает 2 проблемы:
1. Теряется точное место возникновения проблемы (его конечно можно в
теории восстановить из сообщения об ошибке, но это костыль)
2. Если делать расширенную стрингификацию (с полный стэком вызовов),
то сообщение об обшибке после второго вызова будет замусорено.
Есть ли какая-либо возможно побороть эту особенность?
--
С уважением,
Никита Зубков
Подробная информация о списке рассылки Moscow-pm