1. 程式人生 > >Perl的特殊代碼塊:BEGIN、CHECK、INIT、END和UNITCHECK

Perl的特殊代碼塊:BEGIN、CHECK、INIT、END和UNITCHECK

變量 con 代碼 方式 cond second begin require pri

這是5個特殊的代碼塊。要理解這幾個塊,關鍵在於幾個時間點:

  • (1).程序編譯期間
  • (2).程序執行期間
  • (3).程序執行結束但還未退出期間

BEGIN塊

  • BEGIN塊是在程序編譯期間執行的,也就是上面的步驟(1)所在期間
  • 即使程序中出現了語法錯誤,BEGIN塊也會執行
  • 如果出現了多個BEGIN塊,則按照FIFO(first in first out)的方式輸出,也就是從上到下的順序

在BEGIN期間可以做一些程序執行之前的操作,例如事先給某個比較特殊的變量賦值,檢查文件是否存在,檢查操作系統是否滿足要求等等。

package Foo;
use strict;
use warnings;
BEGIN {
    print "This is the first BEGIN block\n";
}

print "The program is running\n";

BEGIN {
    print "This is the second BEGIN block\n";
}

由於BEGIN代碼塊在編譯期間執行,程序普通行的print是在執行期間執行,所以上面的代碼結果為:

This is the first BEGIN block
This is the second BEGIN block
The program is running

下面程序出現語法錯誤,但BEGIN也會執行:

BEGIN {
    print "This is the first BEGIN block\n";
}

print "The program is running\n";

BEGIN {
    print "This is the second BEGIN block\n";
}
my $x =;

執行結果:

syntax error at some_program.pl line 8, near "=;"
Execution of some_program.pl aborted due to compilation errors.
This is the first BEGIN block
This is the second BEGIN block

不過上面的error信息不一定會最先輸出,因為stdout和stderr是兩個獨立的文件句柄,無法保證它們之間的順序。

實際上,use導入模塊時如果導入的是空列表,它等價於在BEGIN中使用require語句:

use File::Find ();
# 等價於
BEGIN {
    require File::Find;
}

END塊

END塊是在程序執行結束,但退出前執行的,也就是上面的步驟(3)所在期間。

  • 當觸發了die的時候,它們也會執行
  • 但可以通過信號來忽略END
  • 它們的執行順序是LIFO(last in first out),即從下往上輸出
  • END常用來做清理、善後操作
END {
    print "This is the first END block\n";
}

END {
    print "This is the second END block\n";
}

輸出結果:註意,先輸出second END,再輸出first END

This is the second END block
This is the first END block

INIT、CHECK 和 UNITCHECK 塊

INIT、CHECK 和 UNITCHECK 塊生效於程序編譯結束之後、執行之前。所以如果語法錯誤,它們不會被觸發。

  • CHECK在編譯結束後立即執行,即上面步驟(1)剛完成之後,輸出格式為LIFO
  • INIT緊跟在CHECK之後,也是在步驟(2)之前,輸出格式為FIFO
  • UNITCHECK是在perl 5.9.5之後引入的功能。用於解決執行期間require或do或eval導入文件時不觸發CHECK和INIT的問題(因為這些語句的導入是在執行期間進行的,而這兩個塊是在編譯期間進行的)。UNITCHECK是在導入的文件剛編譯完成之後、執行之前立即執行的
INIT {
    print "This is the first INIT block\n";
}
CHECK {
    print "This is the first CHECK block\n";
}
INIT {
    print "This is the second INIT block\n";
}
CHECK {
    print "This is the second CHECK block\n";
}

輸出結果:

This is the second CHECK block
This is the first CHECK block
This is the first INIT block
This is the second INIT block

Perl的特殊代碼塊:BEGIN、CHECK、INIT、END和UNITCHECK