あまり意識されていませんが、$@はグローバル変数です。気をつけないとおかしなことになります。以下のコードではdie()で例外を発生させているので「Error is Dummy error」と表示されるように見えますが、表示されません。
package Hoge;
sub new { bless {}, shift }
sub cleanup {
# 色々処理
}
sub DESTROY {
my $self = shift;
eval { $self->cleanup };
}
package main;
eval {
my $hoge = Hoge->new();
die "Dummy error";
};
if ($@) {
print "Error is $@\n";
} else {
print "Everything OK!\n";
}
evalがdie()によって終了し、スコープが切り替わる段階でDESTROYが呼ばれます。その中でeval{}をもう一度呼んでいますが、ここではエラーがなかったため$@が空に設定されるのです。よって、エラーの値を出力するころにはすでに$@は空で、エラーを検知できません。
このようなグローバル変数を変更する可能性のあるコードを書く場合はlocalで修飾すると良いでしょう。
sub DESTROY {
my $self = shift;
local $@;
eval { $self->cleanup };
}
なお、全てのeval{}でこの処理を加える必要はありませんが、該当する箇所にエラーがあってもわざとそれを無視する今回のような場合には明示的にlocalをつけておいたほうが安全です。
次はid:hidekさん