動的生成コードのコンパイル・実行と例外のキャッチを行う
eval
は、指定の Perl のコードを実行しますが、例外を捕捉します。
そして、呼び出し元のプログラムをクラッシュさせないようにするために使います。
eval
に引数を与えなければ、EXPR に $_
が適用されます。
そのため、この引数なしの eval
は、eval EXPR
にすぎません。
そういう意味では、eval
の構文は、
eval EXPR
と eval BLOCK
の 2 つだけとなります。
いずれも前述の通りの役割を持ちますが、その使い方やその利用目的が異なります。
eval EXPR
の構文は "string eval" と呼ばれます。
EXPR には Perl のコードを表す文字列を指定するのですが、
実行したい Perl コードを動的に生成したい場合に使われます。
次のサンプルコードは、コンソールに入力されたモジュール名を require
を使って動的にロードします。
my $mname = $ARGV[0]; # モジュール名を取得
eval "require ${mname};"; # 動的にモジュールをロード
if ($@) {
print "ERROR: $@\n";
}
このように、string eval は、Perl コードを動的に生成し、その場でコンパイル・実行することができます。 また、そのコードが例外を発生させても、その例外はキャッチされ、メインのプログラムは停止しません。 しかし、string eval は外部から入ってきた安全でない文字列ですらコードとして実行してしまいます。 セキュリティの脆弱性の温床になりうるため、利用においては十分な配慮が必要です。
もう一つの構文 eval BLOCK
は "block eval" と呼ばれます。
このブロックには通常の Perl コードを書くのですが、そのコードの実行で例外が発生した場合、
それをキャッチします。その点は string eval と同じです。
この構文は、ブロックに入れたコードが 正常に動作するかどうかを判定したい場合に使います。
eval {
require Digest::SHA;
my $digest = Digest::SHA::sha1_hex('something');
print $digest, "\n";
};
if ($@) {
print "`GD` was not found: $@\n";
}
前述のサンプルコードの通り、string eval であっても block eval であっても、
eval
が実行したコードが例外を発すると、そのエラーメッセージは
$@
にセットされます。
また、string eval であっても block eval であっても、返り値は eval
によって実行されたコードの中で最後の式の値になります。
my $result = eval {
my $str_first = 'FIRST';
my $str_last = 'LAST';
};
print $result, "\n"; # "LAST"
サブルーチンのように return
式も使えます。
my $result = eval {
my $val = 'RETURN';
return $val;
};
print $result, "\n"; # "RETURN"