Perlは元々、システム管理用のスクリプト言語として設計されていたため、従来のエラー処理モデルはより手続き的でした。しかし、時が経つにつれて、言語には例外とエラーの処理に関する高度なテクニックが追加されました。
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 "ファイルを開けません: $!"; while (<$fh>) { print $_; } } catch { warn "エラーが発生しました: $_"; };
$@の上書きやスコープの罠に関連するevalの典型的なエラーを回避できます。evalブロックがシステムエラーをキャッチしない場合はどんな時ですか?
evalは、内部でCライブラリが致命的に終了した場合(例:XSコードからのSEGFAULT)には必ずしもエラーをキャッチしません。evalはPerlの致命的なエラーのみに対処し、C拡張のクラッシュには対応しません。
ネストされたevalブロック内の変数$@はどうなりますか?
eval内でさらに別のevalを呼び出すと、終了時に$@の値が上書きされます。したがって、次のevalまでに$@を別の変数に保存する必要があります。そうしないと、元のエラーを失います。
Try::Tinyのような補助モジュールがなぜcatch/try内で$@変数をローカルに宣言するのですか?
Perlは、try(eval)から正常に退出した場合にのみ自動的に$@をクリアします。エラーで戻る、next、lastは$@がクリアされない原因になり、次のコードでは「ファントム」エラーが生じます。Try::Tinyのようなモジュールは、これを特にためにスコープローカルの変数を作成します。
例:
try { die "バン!"; } catch { print "キャッチ:$_ "; # $_ - catch内のエラー捕獲 };
データエクスポートハンドラーでデータベース接続時にエラーがevalでキャッチされますが、$@の値は保存されず、ログも実行されません。次のevalで別のエラーが発生した時、最初のエラーは完全に失われます。
長所:
短所:
Try::Tinyを使用してクリティカルセクションを処理し、すべてのエラーが別のログに書き込まれ、元のエラーが保持され、正しく画面に出力されます。
長所:
短所: