特殊ファイルハンドル DATA
Perl コンパイラがコードを解釈する段階で、「__END__」もしくは「__DATA__」という行(トークン)を見つけると、それ以降からファイルの終わりまでコードとして解釈されなくなります。コメントのように、何を書いてもコードとしては実行されませんが、これらのテキストは「DATA」という特殊なファイルハンドルで参照する事ができます。
特殊なファイルハンドルといっても、普通のファイルハンドルと同じように行入力演算子(<>)などで読み込む事ができるので、コード中に簡単なデータを埋め込みたい時に便利です。
「__END__」と書いた場合は、どんなパッケージでも常に main パッケージの DATA ファイルハンドル(main::DATA)に関連付けられます。「__DATA__」と書いた場合は、現在のパッケージの DATA ファイルハンドル(__PACKAGE__::DATA)に関連付けられます。
use strict;
while(<DATA>) { print; }
__END__
Hello, world!
I am Palmo the Perl student.
__END__ 以降のテキストがコードとして評価されるとエラーになりますが、実際にはエラーは発生しません。
実行結果は以下の通りです。
Hello, world! I am Palmo the Perl student.
ちゃんと動きますね。(^_^)
__END__ を __DATA__ に変えても動きます。
では、複数のパッケージで試してみましょう。
# Data1.pl
package Data1;
1;
__DATA__
Here is after __DATA__ in Data1
# Data2.pl
package Data2;
1;
__END__
Here is after __END__ in Data2
Data1.pl と Data2.pl として保存します。似たようなコードですが、__DATA__ と __END__ の違いがあります。
パッケージの最後にある式の値はパッケージの評価結果となります。ここでは「1;」として 1 を返しています。パッケージを require する場合、真を返さないとエラーとなってしまうので、その対策です。
use strict;
require "Data1.pl";
require "Data2.pl";
sub show($*) {
my ($name, $data_ref) = @_;
print "$name : ";
while(<$data_ref>) { chomp; print; }
print "\n";
}
show("main", main::DATA);
show("Data1", Data1::DATA);
show("Data2", Data2::DATA);
__END__
Here is after __END__ in main
Data1.pl と Data2.pl をそれぞれ読み込んでいます。show 関数は名前とファイルハンドルを受け取って、その内容を表示する関数です。ファイルハンドルは型グロブとして受け取っています。
これを同じフォルダに保存して実行すると……エラーが発生します。
main : Here is after __END__ in main Data1 : Here is after __DATA__ in Data1 readline() on unopened filehandle at D:\home\palmo\data.pl line 8. Data2 :
Data2::DATA を読み込もうとして、「開かれていないファイルハンドル」とエラーになってしまいました。つまり、Data2::DATA は存在しないという事です。これは、Data2 で __END__ を使っていて、main::DATA に関連付けられたからですね。
試しに Data2 の中の __END__ を __DATA__ に置き換えると、上手く動きます。
# Data2.pl
package Data2;
1;
__DATA__
Here is after __DATA__ in Data2
main : Here is after __END__ in main Data1 : Here is after __DATA__ in Data1 Data2 : Here is after __DATA__ in Data2
メインパッケージ以外では __DATA__ を使う方が無難そうですね。(^_^)