我知道BEGIN块是在Perl程序的主体之前编译和执行的。如果你不确定,只是尝试运行命令perl -cw通过这:
#!/ms/dist/perl5/bin/perl5.8 use strict; use warnings; BEGIN { print "Hello from the BEGIN block\n"; } END { print "Hello from the END block\n"; }
我已经被教导,早期编译和执行BEGIN块允许程序员在执行主程序之前确保任何所需的资源可用。
所以我一直在使用BEGIN块,以确保像DB连接的事情已经建立,并可供主程序使用。类似地,我使用END块来确保所有资源在程序终止之前被关闭,删除,终止等。
今天上午的讨论,我想知道这是错误的方式来看看BEGIN和END块。
BEGIN块在Perl中的预期作用是什么?
更新1:刚刚发现为什么DBI连接没有工作。之后给出这个小Perl程序:
use strict; use warnings; my $x = 12; BEGIN { $x = 14; } print "$x\n";
当执行它打印12。
更新2:感谢Eric Strom的评论下面这个新版本使它更清楚:
use strict; use warnings; my $x = 12; my $y; BEGIN { $x = 14; print "x => $x\n"; $y = 16; print "y => $y\n"; } print "x => $x\n"; print "y => $y\n";
输出为
x => 14 y => 16 x => 12 y => 16
再次感谢埃里克!
解决方法
你试过换出一个INIT {}块的BEGIN {}块吗?这是像modperl这样使用“编译一次,运行多”模型的标准方法,因为您需要在每次单独运行时重新初始化一次,而不是在编译期间一次。
但我必须问,为什么它都在特殊的块。为什么不只是做一些prepare_db_connection()函数,然后在程序启动时根据需要调用它?
如果一个模块文件中的主线代码被使用,那么在BEGIN {}中不起作用的东西也会有同样的问题。这是使用INIT {}块的另一个可能的原因。
我也看到致命的相互递归的问题,必须解开使用类似require而不是使用,或INIT {}而不是BEGIN {}。但这是非常罕见的。
考虑这个程序:
% cat sto-INIT-eg #!/usr/bin/perl -l print " PRINT: main running"; die " DIE: main dying\n"; die "DIE XXX /* NOTREACHED */"; END { print "1st END: done running" } CHECK { print "1st CHECK: done compiling" } INIT { print "1st INIT: started running" } END { print "2nd END: done running" } BEGIN { print "1st BEGIN: still compiling" } INIT { print "2nd INIT: started running" } BEGIN { print "2nd BEGIN: still compiling" } CHECK { print "2nd CHECK: done compiling" } END { print "3rd END: done running" }
当仅编译时,它产生:
% perl -c sto-INIT-eg 1st BEGIN: still compiling 2nd BEGIN: still compiling 2nd CHECK: done compiling 1st CHECK: done compiling sto-INIT-eg Syntax OK
当编译和执行时,它产生:
% perl sto-INIT-eg 1st BEGIN: still compiling 2nd BEGIN: still compiling 2nd CHECK: done compiling 1st CHECK: done compiling 1st INIT: started running 2nd INIT: started running PRINT: main running DIE: main dying 3rd END: done running 2nd END: done running 1st END: done running
而shell报告退出255,每个模具。
你应该能够安排连接发生在你需要的时候,即使BEGIN {}证明太早了。
嗯,只是记得。没有机会你在BEGIN {}中使用DATA做什么,是吗?这直到翻译运行才设置;它不对编译器开放。