北海道苫小牧市出身の初老PGが書くブログ

永遠のプログラマを夢見る、苫小牧市出身のおじさんのちらしの裏

クラスの初期化

perlのクラスの初期化が複雑だと思う今日この頃。例えば、以下のコードの出力はどうなる?


# Class1.pm
package Class1;

print "main Class1\n";
print "#####################\n";

sub import{
print "import Class1\n";
print join(',', @_) . "\n";
print join(',', caller()) . "\n";
print "#####################\n";
}
1;



# Class2a.pm
package Class2a;
use Class1;
use base qw{Class1};

print "main Class2a\n";
print "#####################\n";

1;



# Class2b.pm
package Class2b;
use base qw{Class1};

print "main Class2b\n";
print "#####################\n";

1;



# Another.pm
package Another;
use Class1;

print "main Another\n";
print "#####################\n";

1;



# main.pl
use Class1;
BEGIN{print "==================================\n";}
use Class2a;
BEGIN{print "==================================\n";}
use Class2b;
BEGIN{print "==================================\n";}
use Another;
BEGIN{print "==================================\n";}
require Class2a;
exit(0);





まず、最初のuse Class1だが、useした場合はソースを全て取り込んでからimportを呼ぶことになるので、Class1のメインルーチン、impotサブルーチン、と処理が進むことになる。




use Class1

main Class1
#####################
import Class1
Class1
main,main.pl,1
#####################



次のuse Class2aは、Class2a.pm内でClass1をuseしているが、一度useしたものは取り込まないルールなので、ここではClass1のimport関数だけが呼ばれる。次にClass2aのメインルーチンが実行され、その後perlは、Class2aのimportルーチンを呼び出そうとする。この時点でClass2aはClass1と継承関係が完成しているため、Class1のimportが呼び出される。




use Class2a

import Class1
Class1
Class2a,Class2a.pm,2
#####################
main Class2a
#####################
import Class1
Class2a
main,main.pl,3
#####################




では、use Class2bはどうなるか。このクラスでは、use Class1を行っていない。よって、最初のClass1のimport関数の呼び出しがなくなる。




use Class2b

main Class2b
#####################
import Class1
Class2b
main,main.pl,5
#####################




use Anotherに関しては、Class1との継承関係がない。よって、Another.pmを全て読み終わった後にAnotherのimportルーチンを呼ぼうとしても、呼べるサブルーチンが定義されていないので呼び出すことができない。




use Another

import Class1
Class1
Another,Another.pm,2
#####################
main Another
#####################




最後のrequire Class2aに関しては、Class2a.pmは既に読み込み済なので、何も行わない。requireはuseと違い、importを呼ぶこともない。ちなみにここでrequireの代わりにuseを使うと、Class2aに対するimport関数の呼び出し(継承しているのでClass1のものになるが)だけが行われる。