Перл изначально проектировался как язык скриптов для системного администрирования, потому традиционная модель обработки ошибок была больше процедурной. Однако со временем в языке появились расширенные техники обработки исключений и ошибок.
В первых версиях Perl ошибки ловили через возвращаемые значения функций и проверки глобальной переменной $!, позже появились конструкции eval (динамический захват), а модули вроде Try::Tiny добавили лаконичные, безопасные try-catch-паттерны.
Стандартный Perl не имеет встроенного try-catch-синтаксиса. Ошибки могут возникать как в Perl-коде, так и во внешних вызовах (например, открытие файлов). Если не обрабатывать ошибки явно, программа может продолжить работу в непредсказуемом состоянии. Необходимо грамотно выбирать технику перехвата ошибок в зависимости от контекста, сложности приложения и требований к надежности.
eval, оборачивая потенциально опасный код в блок и анализируя содержимое $@ после выполненияdie. Более точечная генерация ошибок и повторное возбуждение уже описанных исключений — через каркас sinonПример кода — обработка ошибок через Try::Tiny:
use Try::Tiny; try { open my $fh, '<', 'file.txt' or die "Can't open file: $!"; while (<$fh>) { print $_; } } catch { warn "Произошла ошибка: $_"; };
$@ и scope-ловушкамиВ каком случае eval-блок не перехватит системную ошибку?
Eval не всегда перехватывает ошибку если внутри происходит фатальный выход в C-библиотеках (например, SEGFAULT из XS-кода). Eval работает только с Perl-фатальными ошибками, а не с крахами С-расширений.
Что произойдет с переменной $@ при вложенных eval-блоках?
Если внутри eval вызвать еще один eval, то при его выходе значение $@ перезапишется. Поэтому после каждого eval стоит сохранять $@ в отдельную переменную до следующего eval, чтобы не потерять оригинальную ошибку.
Для чего вспомогательные модули типа Try::Tiny объявляют переменную $@ локально внутри catch/try?
Потому что Perl автоматически очищает $@ только при успешном выходе из try (eval). Возврат по ошибке, next, last может привести к тому, что $@ останется неочищенным, и в следующем коде будет "фантомная" ошибка. Модули типа Try::Tiny делают scope-local переменную специально для этого.
Пример:
try { die "Boom!"; } catch { print "Поймали: $_ "; # $_ - ловушка ошибки внутри catch };
В обработчике экспорта данных ошибка при подключении к БД ловится через eval, но значение $@ не сохраняется, логирование не выполнено. Когда в следующем eval вызывается другая ошибка, первая полностью теряется.
Плюсы:
Минусы:
Использование Try::Tiny для обработки критических секций, все ошибки пишутся в отдельный лог, оригинальная ошибка сохраняется и корректно выводится на экран.
Плюсы:
Минусы: