eval

動的生成コードのコンパイル・実行と例外のキャッチを行う

構文

解説

eval は、指定の Perl のコードを実行しますが、例外を捕捉します。 そして、呼び出し元のプログラムをクラッシュさせないようにするために使います。

eval に引数を与えなければ、EXPR$_ が適用されます。 そのため、この引数なしの eval は、eval EXPR にすぎません。 そういう意味では、eval の構文は、 eval EXPReval 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"