実行時にライブラリーから外部関数をロードする
require
には、Perl 本体のバージョン番号を指定して該当の Perl プログラムがそれより以前のバージョンで動作しないようにする機能、
そして、引数に指定したモジュールをロードする機能の 2 つの役割があります。
require VERSION
構文の場合は、Perl のバージョンが VERSION
に指定したバージョン以上であることを要求します。
もし VERSION が現在の Perl インタプリタのバージョンより大きい場合は例外が投げられます。
VERSION には v5.24.1 のようなリテラルを指定することができます。
これは $^V
(または、English
の $PERL_VERSION
) にセットされている値の形式と同じです。
VERSION には 5.024001 のような形式の数値で指定することもできます。
これは $]
にセットされている値の形式と同じです。
しかしこういった形式の数値を VERSION に指定するのは一般的には避けるべきです。
なぜなら、v5.24.1 という表記と比べて、古くて読みづらい構文だからです。
2002 年にリリースした Perl 5.8.0 より前では、もっと冗長な数値形式しか構文としてサポートされていませんでした。
そのため、次のようなコードを見たことがあるかもしれません。
require v5.24.1; # 推奨の形式
require 5.24.1; # 先頭に v がないが許されている
require 5.024001; # 読みづらいので非推奨
require 5.024_001; # Perl 5.6 時代の古い構文なので、現在は非推奨
require EXPR
構文は、モジュールファイルを現在のスクリプトに組み込みます。
EXPR が省略された場合は $_
が適用されます。
同じファイルを指定している限り、何度 require
を実行しても、最初の 1 度しか読み込まれません。
歴史的に、モジュールファイルは初期化コードの実行が成功したことを示すために、最後のステートメントで true を返さなければいけません。
一般的にはモジュールファイルの最後を 1;
とすることが慣例になっています。
しかし、Perl 5.37.6 以降なら、use feature 'module_true';
とすれば 1;
は不要です。
または、use v5.37;
でも 1;
を書かなくても良くなります。
EXPR がベアワードなら、require
は、EXPR の値からモジュールファイルを検索します。
次の例を使って、モジュールファイルの検索方法を解説します。
use Foo::Bar;
このモジュールのファイルを検索する際に、まずモジュールのファイル拡張子は .pm だと仮定します。
次に EXPR の値の中に ::
が存在すれば、それを /
に置換します。
もし EXPR が Foo::Bar
なら、Foo/Bar.pm
になります。
次に特殊変数 @INC
の中にセットされているパスを最初から順に走査します。
もし @INC
が ('/usr/share/perl5', '/usr/local/lib/site_perl')
だったとすると、次の順にファイルを探すことになります。
/usr/share/perl5/Foo/Bar.pm /usr/local/lib/site_perl/Foo/Bar.pm
このように @INC
のディレクトリパスを検索対象にすることから、
EXPR にベアワードを指定する方法は主に標準モジュールをロードしたい場合に使われます。
しかし、Foo::Bar
を文字列として指定すると、それはファイルパスとみなされるため、上記の変換は行われません。
my $class = 'Foo::Bar';
require $class; # $class はベアワードではない
#または
require "Foo::Bar"; # "" を使っているためベアワードではない
もし、どうしても文字列で指定したいなら、次のように eval
を使います。
eval "require $class";
または、該当のモジュールのファイルパスを指定します。
この場合でも前述の @INC
のディレクトリパス検索は有効です。
require "Foo/Bar.pm";
以上、require
がベアワードの引数からどうやってファイルを探すのかを解説しましたが、
裏で進行している機能がもう少しあります。
require
は、拡張子 .pm を探す前に、拡張子が .pmc のファイルを検索します。
このファイルが見つかれば、拡張子 .pm のファイルの代わりに、それをロードします。
これは、明示的な require "Foo/Bar.pm";
の形式と
require Foo::Bar;
の形式の両方に当てはまります。
use
と require
の違いuse
と require
はいずれもモジュールをロードする役割を持ちます。
しかし、それぞれ異なる点があります。
もっとも大きな違いは、モジュールをロードするタイミングです。
use
はコンパイル時に処理されます。
一方、require
はスクリプトの実行時に処理されます。
この違いは、状況によってモジュールをロードするかを決定したい場合に問題となります。
もしそうしたい場合は、require
を使います。
require
は実行時にモジュールを読み込むため、if
などのフロー制御が効きます。
if ( $^O eq 'MSWin32' ) {
require './MyPackage.pm';
}
もし、ここで require
の代わりに use
を使うと、
コンパイル時に処理されてしまうため、if
の存在に関わらず、モジュールをロードしようとします。
次に、use
と require
の違いとして大きいのは、
use
は読み込むモジュールに import
関数があれば、
それを呼び出す点です。require
は import
関数を呼び出しません。
import
関数は、多くのモジュールで
Exporter が使われています。
これは、モジュールが提供する変数や関数を、呼び出し元の名前空間にインポートします。
たとえば、Foo::Bar
モジュールに do_something
という関数が実装されていたとしましょう。
本来なら、そのメソッドを呼び出す際には、Foo::Bar::do_something()
のように名前空間も含めた完全修飾名でコードに書く必要があります。
しかし、Exporter によって、あたかも自身の関数であったかのように do_something()
で呼び出すことができます。
次のコードは、File::Copy の例です。
use File::Copy;
copy( 'orig.txt', 'copy.txt' );
このコードでは use
を使って File::Copy をロードしたため、
File::Copy の copy
関数が呼び出し元の名前空間にインポートされます。
そのため、完全修飾名をコードに書く必要がありません。
一方、もし File::Copy を require
でロードすると、
copy
関数は完全修飾しないと呼び出すことができません。
require File::Copy;
File::Copy::copy( 'orig.txt', 'copy.txt' );
また、require
は eval
でモジュールが見つからなかった場合の処理を書くことが可能です。
eval { require Foo::Bar; };
if ($@) {
print "Foo::Bar が見つかりませんでした: $@\n";
}
use
では、コンパイル時にモジュールをロードしようとするため、
これを実現することはできません。
use
の場合、もしモジュールが見つからなければ例外が投げられてしまい、
強制的にスクリプトは終了してしまいます。