毎秒1000リクエスト を捌く超高速CMS「adiary」
2007/01/13(土)perl の import の働き
use と require と import の関係
perldoc perlmodによると、use というのは次と等価と書かれています。
use Module; use Module LIST;
はそれぞれ、
BEGIN { require Module; import Module; } BEGIN { require Module; import Module LIST; }
と等価になります。
BEGINとは?
BEGIN というのは、perl がそのソースファイルをロード中、発見次第最初に1回だけ実行する構文であるという意味です。少しフォローしておくと、モジュールのロードは、@INCにあるパスを順番に見てロードされますが、lib/ 以下に自作モジュールがあるとき、
push(@INC, './lib'); use Module;
はエラーとなります。先に use (BEGIN内構文)が実行されて、@INCにパスを追加する前にモジュールのロードが発生するからです。
use lib './lib'; use Module;
や、
push(@INC, './lib'); require Module; import Module;
とする必要があります。END { }なんてのもありますが、脱線はこれぐらいにして本題に入りましょう。
import がない場合
モジュールをロードし perl の名前空間に展開するならば、基本的には require すれば足ります。
---test.pm--- package test; sub new { return bless({}, shift); } ---test.pl--- require test; my $obj = new test();
ちなみに require では実行する度に処理されてしまうので無駄になりますから、
use test (); BEGIN { require test; } と等価
とします。import しなくても、ロードしたライブラリを使えるわけです。ではインポートとは何なのか?
import の役割
import は外部ライブラリの関数をあたかも自分の関数のように扱う仕組みです。正確に言えば、外部ライブラリの関数を自分の名前空間内に展開する仕組みが import です。例を見てみましょう。
---test.pm--- use Exporter; #←必須です package test; our @ISA = qw(Exporter); #←必須です our @EXPORT = qw($X &sum); our @EXPORT_OK = qw($Y); our $X = 10; our $Y = 20; sub sum { return ($_[0]+$_[1]); #渡された引数2つを加えて返す処理 } print "in test.pm : X=", \$X, "\n";
呼び出し側はこんな感じです。
use test; # BEGIN {require test; import test;} と等価
our ($X, $Y);
print "X=$X ", \$X, "\n";
print "Y=$Y\n";
print sum(5,3),"\n";
として実行してみます。
in test4.pm X=SCALAR(0x93bc130)
X=20 SCALAR(0x93bc130)
Y=
30
となります。test という名前空間内の変数 $X、関数 sum が、import した側で使えるようになっています。perl 的に正確に言えば、$test::x と &test::sum の示す実体が(内部的な実体のポインタが)それぞれ $MAIN::x、&MAIN::sum にコピーされたことになります。その証拠に、リファレンスをとって実体を調べると、ともに同じ実体である SCALAR(0x93bc130) を示しています。
import される関数は、モジュール側で @EXPORT に代入されているものになります。
import の引数は何?
import は配列引数を取れることになっています。これは、モジュール側で @EXPORT および @EXPORT_OK に代入されているもののうち、どれをインポートするか指定する役割があります。
ですから、さきほどのソースで、
use test qw(&sum $Y);
と変更すると次のような結果になります。
in test4.pm X=SCALAR(0x953e1b8)
X= SCALAR(0x94fd660)
Y=10
30
$Yがインポートされている反面、$X が test.pm 内の実体とは違うものを示していることが分かります。