W Perl obsługa błędów tradycyjnie realizowana jest za pomocą funkcji die, warn oraz bloku eval. Dla poprawnego zakończenia programu zaleca się użycie die dla krytycznych błędów, a do ostrzeżeń — funkcji warn. Drugim sposobem jest użycie operatora blokowego eval do przechwytywania poważnych błędów z późniejszym ich przetwarzaniem.
Przykład:
open my $fh, '<', 'file.txt' or die "Nie można otworzyć pliku: $! "; printf $fh "Hello" or warn "Nie można zapisać: $! "; # Obsługa błędu za pomocą eval my $result = eval { risky_function(); 1; }; unless ($result) { print "Wykryto błąd: $@ "; }
Istnieją również moduły takie jak Try::Tiny i Error, które realizują try/catch dla Perla.
Jaka jest różnica między użyciem eval {} a ciągiem eval "...", i jakie pułapki ma każdy z tych sposobów?
Wielu błędnie uważa, że są identyczne.
eval { ... }działa jak blokowy try/catch, podczas gdyeval "..."kompiluje i wykonuje ciąg jako kod Perl w czasie wykonywania. Przy użyciu ciągu łatwo popełnić błąd i potencjalnie narażamy kod na SQL injection lub błędy kompilacji.
Przykład różnic:
# Kompiluje i wykonuje ciąg jako kod Perl my $var = 'my $x = 2 + 2'; eval $var; # eval BRUDNY! # Bezpieczna wersja blokowa my $error = eval { die "fail"; }; print $@ if $@;
Historia
W jednym projekcie deweloperzy używali eval "kod" do dynamicznego formowania poleceń, co doprowadziło do nieosiągalnych błędów składni w czasie wykonywania i problemów z debugowaniem.
Historia
Niepoprawne przechwytywanie błędów: wyjątki wywołane wewnątrz eval z użyciem lokalnych zmiennych nie były obsługiwane, ponieważ $@ był nadpisywany następnym wywołaniem funkcji log.
Historia
W starym kodzie zamiast try/catch stosowano tylko die(), co prowadziło do niekontrolowanego zakończenia procesu Perl i utraty danych w transakcjach bazy danych.