NeverBlog::Likk::Unexistable;

見なかったことにして下さい

DESTROY中はdieで死ねない。

Perl には生成したオブジェクトが参照されなくなったとき、またはスコープから外れた時に自動的に開放されるわけですが、その開放直前に何かさせたい時に DESTROY method を用意することでそれを実行することができます。

package Hoge;
use strict;
use warnings;

{
    sub new {
        my $class = shift;
        my %args = @_;
        return bless { %args }, $class;
    }

    sub DESTROY {
        print "destory\n";
    }
}


package main;

print "start\n";

{
    my $hoge = Hoge->new;
    print ref $hoge . "\n";
}   #$hogeがスコープから外れる

print "end\n";
start
Hoge
destory
end

とこんな感じに、スコープから外れた時にdestoryが出力されます。

では、このprintをdieに変えたらどうなるか。

start
Hoge
        (in cleanup) destory
end

と、(in cleanup) destory と出力されるものの、ここで死なず最後のendの出力まで実行されます。
原因を調べていませんが、死んで欲しい箇所で死んでくれなかったのでハマったのでブログにあげてみた。

実際やりたいことは何かというと、以下な感じでスコープから外れるときに特定条件を満たさないときはエラーにしたかった。

package Hoge;
use strict;
use warnings;
use Class::Accessor::Lite ( rw => [qw/is_modify/]);

{
    sub new {
        my $self = bless { data => 1 }, shift;
        $self->is_modify(0);
        return $self;
    }

    sub set_data { #ここではインスタンスデータを更新だけ
        my $self = shift;
        my $data = shift;
        $self->{data} = $data;
        $self->is_modify(1);
    }

    sub get_data { return shift->{data} }

    sub update {
        my $self = shift;
        #まーなんか、DBに書き込む処理
        $self->is_modify(0);
    }

    sub DESTROY {
        my $self = shift;
        die 'update してないよ><' if $self->is_modify;

    }
}

package main;

{   #普通に参照する分には大丈夫
    my $hoge = Hoge->new;
    warn ref $hoge;
    warn $hoge->get_data;
}

{   #なんかsetしても最後にupdateすれば大丈夫
    my $hoge = Hoge->new;
    $hoge->set_data(11);
    warn $hoge->get_data;
    $hoge->update;
}

{
    my $hoge = Hoge->new;
    $hoge->set_data('AAAAA');
    warn $hoge->get_data;
    #$hoge2->update; updateするのを忘れる
}   #スコープを抜けるときに怒られる!!

warn 'end';