Perl został pierwotnie zaprojektowany jako język skryptowy do administracji systemowej, dlatego tradycyjny model obsługi błędów był bardziej proceduralny. Z biegiem czasu w języku pojawiły się rozszerzone techniki obsługi wyjątków i błędów.
W pierwszych wersjach Perla błędy łapano poprzez zwracane wartości funkcji i sprawdzanie globalnej zmiennej $!, później pojawiły się konstrukcje eval (dynamiczne przechwytywanie), a moduły takie jak Try::Tiny dodały zwięzłe, bezpieczne wzorce try-catch.
Standardowy Perl nie ma wbudowanego składni try-catch. Błędy mogą występować zarówno w kodzie Perl, jak i w wywołaniach zewnętrznych (np. otwieranie plików). Jeśli błędy nie są obsługiwane jawnie, program może kontynuować działanie w nieprzewidywalnym stanie. Należy mądrze wybierać technikę przechwytywania błędów w zależności od kontekstu, złożoności aplikacji i wymagań dotyczących niezawodności.
eval, otaczając potencjalnie niebezpieczny kod w bloku i analizując zawartość $@ po wykonaniudie. Bardziej precyzyjne generowanie błędów i ponowne zgłaszanie już opisanych wyjątków — za pomocą frameworka sinonPrzykład kodu — obsługa błędów przez Try::Tiny:
use Try::Tiny; try { open my $fh, '<', 'file.txt' or die "Nie można otworzyć pliku: $!"; while (<$fh>) { print $_; } } catch { warn "Wystąpił błąd: $_"; };
$@ i pułapkami scopeW jakim przypadku blok eval nie przechwyci błędu systemowego?
Eval nie zawsze przechwytuje błąd, jeśli w środku dochodzi do fatalnego wyjścia w bibliotekach C (np. SEGFAULT z kodu XS). Eval działa tylko z fatalnymi błędami Perla, a nie z awariami rozszerzeń C.
Co się stanie z zmienną $@ w zagnieżdżonych blokach eval?
Jeśli wewnątrz eval wywoła się jeszcze jeden eval, to po jego wyjściu wartość $@ zostanie nadpisana. Dlatego po każdym eval warto przechowywać $@ w osobnej zmiennej do następnego eval, aby nie stracić oryginalnego błędu.
Dlaczego pomocnicze moduły typu Try::Tiny deklarują zmienną $@ lokalnie wewnątrz catch/try?
Ponieważ Perl automatycznie czyści $@ tylko przy pomyślnym wyjściu z try (eval). Powrót w przypadku błędu, next, last może spowodować, że $@ pozostanie nieczyszczony i w następnym kodzie będzie „widmo” błędu. Moduły typu Try::Tiny tworzą zmienną scope-local właśnie w tym celu.
Przykład:
try { die "Boom!"; } catch { print "Złapano: $_ "; # $_ - pułapka błędu wewnątrz catch };
W obsłudze eksportu danych błąd podczas łączenia z bazą danych jest łapany przez eval, ale wartość $@ nie jest zapisywana, logowanie nie zostało wykonane. Gdy w następnym eval występuje inny błąd, pierwszy jest całkowicie tracony.
Zalety:
Wady:
Użycie Try::Tiny do obsługi krytycznych sekcji, wszystkie błędy są zapisywane w osobnym logu, oryginalny błąd jest zachowywany i poprawnie wyświetlany na ekranie.
Zalety:
Wady: