perlのコードでよく見かけるrequire、use、BEGINの役割や関係についてまとめる

最近Perlを触り始めたのだが、ソースコードを見るとrequireとかuseとかBEGINと言ったキーワードをよく見かけるので、今のうちにまとめておく。

perlにおけるrequireの使い方

まずuseの前にrequire関数の使い方を解説する。

require関数とは、「ファイルを読み込んでくれる関数のことで、C言語やphpで言うinclude、Rubyで言うrequireと同じものと言える。

例えば、ModuleディレクトリにあるConfig.pmを読み込みたい、と言う場合は以下の様に書くことができる。

require './Module/Config.pm';

上記の様な書き方は他言語でもよく見かけるが、perlでは以下の書き方の方が一般的。

require Module::Config;

requireの進化バージョン use

ほぼrequire関数の正統進化と言えるのが、use関数となる。userequireに比べて簡潔に表現できるし、細かい設定までできる。

use Module::Config;

useがやってくれることは、ほぼrequireと変わらない。と言うより、use Module::Config;と言うコードは以下のコードと全く同じ意味を持つ。

BEGIN {
require Module::Config;
Module::Config->import;
}

また、useに第2引数を持たせることで、上記の二行目にあるimport関数に引数を与えることができる。

use Module::Config  qw(get_name set_name);
= これと同等のコード
BEGIN {
require Module::Config;
Module::Config->import qw(get_name set_name);
}

useで出てくるBEGINとかimportって何なの?

useに出てくるBEGINとかimportとかは、どんな役割があるのだろうか?

まずは、BEGINから見ていく。

BEGINについて

実は、perlのプログラムが実行される時には、以下の2つの手順を踏んでいる。

  • コードを実行しやすい様に書き換える(C/C++のプリプロセッサ的な処理)
  • 実際にコードを実行する

先ほど出たBEGINは、最初の「コードを実行しやすい様に書き換える」段階で実行されて、良い感じのコードに書き換えてくれる。

少し長いけど、公式ドキュメントでは以下の様に説明されている。

BEGIN コードブロックは、できるだけ早く、つまり、たとえファイル (または文字列)の残りが解析されていなくても、定義された瞬間に実行されます。 ファイル(または eval された文字列)内に複数の BEGIN ブロックを 置くこともできます; それらは定義された順番に実行されます。 BEGIN ブロックは即座に実行されるので、サブルーチンなどの定義を 他のファイルから読み込んでコンパイル時と実行時の残りの部分から見えるように することができます。 BEGIN が実行されれば、それは即座に未定義になり、使われたコードの 全ては Perl のメモリープールに返されます。

perlmod – Perl のモジュール (パッケージとシンボルテーブル) – perldoc.jp

useのimport関数について

2つ目のimportだが、これはperlが用意してくれている組み込み関数ではなくて、プログラマが自身で作る関数となる。

この説明だけだと分かりにくいので、実験的に以下のコードを用意してみた。

# main.pl
use Sample;
# Sample.pm
package Sample;
sub import {
print "hello\n";
}
1;

上記は、import関数だけを定義したSampleモジュールとそのSampleモジュールを読み込むだけのmain.plを用意した。

これをperl main.plで実行すると、結果はhelloと出た。つまり、use Sample;とモジュールを読み込んだだけで、import関数も呼び出されたことが分かる。

import関数はどの様に使えば良いか?

もちろん、上記の例で示したコードの様な使い方ではなく、import関数はモジュール内で定義した関数をより呼びやすくするために使われることが多い。

package Sample;
sub import {
my $class = shift;
for (@_) {
*{"main::$_"} = \&$_;
}
}
sub hello {
print "hello";
}
1;

普通、perlでモジュール内で定義された関数をモジュール外から呼び出す時には、Sample::helloの様にしなければいけない。Sample::helloの様な簡潔なモジュール名だと問題ないが、Sample::Validation::Userみたいな長いモジュール名だと呼び出す時も大変になる。

そこで上記のimport関数内の処理をすることでSample::helloではなくて、helloと書くことでSample::helloを呼び出すことができる、というのがimportの働きになる。

perlのimportに関する情報ってあまりなくて、perlの公式ドキュメントの解説も非常に素っ気無い内容になっている。

組み込みの import 関数というものはありません。 これは単に、別のモジュールに名前をエクスポートしたいモジュールが 定義した(または継承した)、通常のメソッド(サブルーチン)です。 use 関数はパッケージを使う時に import メソッドを呼び出します。 use, perlmod, Exporter も 参照してください。
Perlの組み込み関数 import の翻訳 – perldoc.jp

上記の様に自前でimport関数を作るのも酔いが、ベストプラクティスはExporterモジュールを使うことだろう。Exporterを使うことで、関数の呼び出しを簡単にできる様になる。

参考:Exporter – perldoc.perl.org

requireとかuseはどのようにファイルを見つけてくるのか

requireuseがどのようにファイルを見つけてくるかと言うと、perlが定義している@INC配列をチェックして、指定されたファイルを探している。

例として以下のコードを実行してみると分かりやすい。

use 5.10.0;
for (@INC) {
say $_;
}
----result-----
/home/user/.plenv/versions/5.14.2/lib/perl5/site_perl/5.14.2/x86_64-linux
/home/user/.plenv/versions/5.14.2/lib/perl5/site_perl/5.14.2
/home/user/.plenv/versions/5.14.2/lib/perl5/5.14.2/x86_64-linux
/home/user/.plenv/versions/5.14.2/lib/perl5/5.14.2
.

上記の結果を見ると分かるように、これらのディレクトリを見ることで指定されたファイルを読み込もうとしている。(ちなみに、cpanm等でインストールしたモジュールはデフォルトでは/home/user/.plenv/versions/5.14.2/lib/perl5/site_perl/5.14.2に保存される。)

なので、「libディレクトリに自作モジュールを置いて、そこで読み込ませたいな」と考えた場合は、以下の様にして@INC配列にlibディレクトリを追加してあげればよい。

BEGIN { unshift @INC, "lib" }
use Module::Config;
my $config = Module::Config->new( name => 'tarou', );

ReratedPosts

perlでIO::Socketを使う時に「permission deny」と言うエラーが出た時の対処法
perlで正規表現で文字列を置換したり、新しい変数に格納する方法
Mojoliciousを使う時のMojo::Base -baseとかの使い分けのまとめ
Mojoliciousで「[error] Role::Tiny 2.000001+ is required for roles」のエラーが出た時の対処法
perl(Mojolicious)をレンタルサーバーXserverを使って公開する手順まとめ
Mojoliciousでディレクトリの場所を変数(属性)として格納する方法