Unless you really know what you are doing.

antipop2.0: Perl で楽々アクセサ作成について考えてみた
hio (September 9, 2005 10:12 PM)
ちょっと変なコトしてみました. (perl 5.8.3以降じゃないとSEGVするみたいです)
http://fleur.hio.jp/~hio/accessor.pl
kentaro (September 10, 2005 12:28 AM)
どうもどうもです! UNIVERSAL::AUTOLOAD をいじるコードとか、初めてみましたよ! なるほどそういうやり方もあるんですねぇ。奥が深い……。

感心している場合じゃないって!

&UNIVERSAL::AUTOLOADを定義するというのは、あまりに推奨できない方法です。&AUTOLOADを定義せず、かつ@ISAの中にあるパッケージのいずれも定義していないパッケージでは全てこれが使われてしまい、あまりに危険です。未定義のmethodをきちんとエラーとしてPerlに捕まえて欲しい時にもなんでもありになっちゃいます。このレベルの「邪道」は、本当にわかっていないと危なすぎる、筋弛緩剤クラスの危険度です。少なくともno strict;より危険。

こういうModuleが、例えば複数人で開発しているmod_perlベースのサイトに突っ込まれたときのことを考えても見て下さい。

#「救急病棟」レベル10の人がむやみにUNIVERESAL::に頼っちゃ行けませんなあ

同じ事をしたいのであれば、継承を使えばいいだけの話です。

package Class::Accessor::Nested;
use Carp;
sub AUTOLOAD {
    my $this = shift;
    my $name = our $AUTOLOAD;
    $name =~ s/.*:://o;
    $name eq 'DESTROY' and return;
    ref($this) && $name or croak "Undefined subroutine $name called";
    @_ and $this->{$name} = shift;
    ref $this->{$name} eq 'HASH' and bless $this->{$name}, ref($this);
    $this->{$name};
}

1;

とでも定義しておき、

package MyData;
use base 'Class::Accessor::Nested';
sub new{
  my $pkg = shift;
  my $data = shift || {};
  bless $data, $pkg;
}

として使えば良い。Testしたらちゃんと動きましたよ。

さらに、以下のようにすれば、二度目の呼び出し以降は&AUTOLOADが呼び出されることすらありません。

sub AUTOLOAD {
    my $this = shift;
    my $name = our $AUTOLOAD;
    $name =~ s/.*:://o;
    $name eq 'DESTROY' and return;
    ref($this) && $name or croak "Undefined subroutine $name called";
    {
        no strict 'refs';
        *$name = sub {
            # warn "$name predefined";
            my $self = shift;
            @_ and $self->{$name} = shift;
            ref $self->{$name} eq 'HASH' and bless $self->{$name}, ref($self);
            $self->{$name};
        };
    }
    # warn "$name first called";
    @_ and $this->{$name} = shift;
    ref $this->{$name} eq 'HASH' and bless $this->{$name}, ref($this);
    $this->{$name};
}

実はこの辺の話題はラクダ本にもきちんと出てきます。車輪や毒を再発明する前にきちんと目をとおしておきましょう。

Dan the Just Another AUTOLOAD Hacker