use vs require in Perl5

Perl5 的程序執行分爲兩個階段:compilation time & run time。而 use 與 require 依次發生在這兩個不同的階段。
值得注意的是:Parser對use的處理等同如下:

use strict;

like

BEGIN{
    require 'strict.pm';
    strict->import();
}

NOTE:BEGIN block是在compilation time觸發執行(賦值)過程。

也就是說,strict 中所定義的variables & subroutines已於compilation time在data structure(optree)中賦值並存在了。
接下來通過對不同路徑下,擁有相同包package name or file name的文件導入來分析它們的不同表現。

use PACKAGE;

/tmp/amy_dir/hello.pm

sub say(){
    print "Hello! I am Amy\";
}
1;
__END__;

/tmp/bob_dir/hello.pm

sub say(){
    print "Hello! I am Bob\";
}
1;
__END__;

/tmp/say_hello.pl

use lib "/tmp/amy_dir";
use hello;
hello->say();

use lib "/tmp/bob_dir";
use hello;
hello->say();

運行結果:

[root@VTB93-PC1 tmp]# perl say_hello.pl
Hello! I am Amy
Hello! I am Amy

分析:上面提到 use 等同 BEGIN{…}。amy_dir目錄下的 hello.pm 先被賦值於optree中, 後續Parser再遇上 bob_dir下的hello.pm時,發現optree中已存在以此包名爲值的 key,將不再進行二次賦值。所以在 run time 順序執行代碼時,所有對 hello->say() 的調用都是參照/tmp/amy_dir/hello.pm

require “some_file.pl(pm)”;

Perl5對 require 的處理是在 run time。當執行require時會在run time觸發編譯。
接下來將/tmp/say_hello.pl中的 use 部分替換成 require 後:

[root@VTB93-PC1 tmp]# vi say_hello.pl

use lib "/tmp/amy_dir";
require 'hello.pm';
hello->say();

use lib "/tmp/bob_dir";
require 'hello.pm';
hello->say();

運行結果:

[root@VTB93-PC1 tmp]# perl say_hello.pl
Hello! I am Bob
Hello! I am Bob

分析:在run time 執行到 require 語句觸發編譯。這邊可以理解爲 say_hello.pl 中最終包含了 /tmp/bob_dir/hello.pm 中的代碼。這是由於 @INC 中的優先路徑爲 /tmp/bob_dir/。導致 @INC 如此的是由於編譯時,兩次 use lib 操作的順序所致。

[root@VTB93-PC1 tmp]# perl say_hello.pl
Hello! I am Bob
Dump @INC
(
  "/tmp/bob_dir",
  "/tmp/amy_dir",
  "/usr/local/lib/perl5",
  "/usr/local/share/perl5",
  "/usr/lib/perl5/vendor_perl",
  "/usr/share/perl5/vendor_perl",
  "/usr/lib/perl5",
  "/usr/share/perl5",
  ".",
)
Hello! I am Bob
Dump @INC
(
  "/tmp/bob_dir",
  "/tmp/amy_dir",
  "/usr/local/lib/perl5",
  "/usr/local/share/perl5",
  "/usr/lib/perl5/vendor_perl",
  "/usr/share/perl5/vendor_perl",
  "/usr/lib/perl5",
  "/usr/share/perl5",
  ".",
)

結論:

  1. 先後 use 不同路徑下,擁有相同package name的 pm,只會導入第一個pm
  2. 先後 require 不同路徑下,擁有相同name的pl or pm file, 只會導入後一個file
  3. use lib LIST, 對@INC進行unshift操作
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章