В Perl обработка ошибок традиционно осуществляется с помощью функций die, warn, а также блока eval. Для корректного завершения программы рекомендуется использовать die для критических ошибок, а для предупреждений — функцию warn. Второй способ — использование блочного оператора eval для перехвата фатальных ошибок с последующей их обработкой.
Пример:
open my $fh, '<', 'file.txt' or die "Can't open file: $! "; printf $fh "Hello" or warn "Couldn't write: $! "; # Обработка ошибки с помощью eval my $result = eval { risky_function(); 1; }; unless ($result) { print "Error detected: $@ "; }
Также существуют модули типа Try::Tiny и Error, реализующие try/catch для Perl.
Какова разница между использованием eval {} и строки eval "...", и какие подводные камни есть у каждого из способов?
Многие ошибочно думают, что они идентичны.
eval { ... }работает как блочный try/catch, аeval "..."компилирует и выполняет строку как Perl-код во время выполнения. При использовании строки легко допустить ошибку и потенциально подвергнуть код SQL-инъекциям или багам компиляции.
Пример отличий:
# Компилирует и выполняет строку как Perl-код my $var = 'my $x = 2 + 2'; eval $var; # eval DIRTY! # Безопасный блочный вариант my $error = eval { die "fail"; }; print $@ if $@;
История
В одном проекте разработчики использовали eval "код" для динамического формирования команд, что привело к недосягаемым ошибкам синтаксиса на этапе выполнения и проблемам отладки.
История
Некорректный перехват ошибок: исключения, вызванные внутри eval с использованием локальных переменных, не были обработаны, так как $@ затирался последующим вызовом функции log.
История
В старом коде вместо try/catch применяли только die(), что вызывало неуправляемое завершение процесса Perl и потерю данных в транзакциях базы данных.