実行時にライブラリーから外部関数をロードする
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 の場合、もしモジュールが見つからなければ例外が投げられてしまい、
強制的にスクリプトは終了してしまいます。