あまり意識されていませんが、$@
はグローバル変数です。気をつけないとおかしなことになります。以下のコードでは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さん