我试图了解use vars ($var);
是如何工作的。我意识到,如果我想全局声明一个变量,我可以使用use vars ($var);
或Perl5.6或更高版本,我可以用our $var;
然而,我仍在努力了解它是如何工作的。从源代码来看,您只需将变量声明为typeglob,并将其设置为自身的引用版本。什么!?
# My_Module.pm
use strict (vars, subs);
use CGI::Carp;
*My_Module::My_Global = $My_Module::My_Global;
sub my_function {
$My_Global = 'Am I declared?';
}
现在这不起作用,我显然得到了一个"未定义的符号"错误。那么use vars
是如何做到的呢?
----------------更新----------------
我完全复制了你的代码,用use X;
而不是shell从test.cgi运行它。。。
X.pm
use strict;
BEGIN { package X; no strict qw( refs ); *main::x = ${"main::x"}; }
print "Content-type: text/htmlnn"; # I added this line since not printing to shell
$x = 123; say $x;
1;
test.cgi
#!/usr/bin/perl
use strict;
use X;
我得到了和以前一样的编译错误:
Global symbol "$x" requires explicit package name at X.pm line 4.
这只适用于外壳而不适用于模块吗?
为typeglob指定引用是一种特殊的赋值;它只将引用类型的typeglob的一部分替换为引用。此外,vars对变量名使用了符号引用,而您没有使用符号引用。use vars
也在不同的包中执行,并且在编译时执行,而不是在运行时执行。内联等价物是:
BEGIN { package foo; *My_Module::My_Global = ${"My_Module::My_Global"} }
也就是说,使用全局变量通常是个坏主意。使用不再受支持的perl版本同样是个坏主意。
只需使用一个变量即可将其创建为(全局)包变量。
$ perl -wE'$x = 123; say $x;'
123
这是非常危险的,所以程序员告诉Perl使用use strict qw( vars );
来禁止这种情况。
$ perl -wE'use strict; $x = 123; say $x;'
Global symbol "$x" requires explicit package name at -e line 1.
Global symbol "$x" requires explicit package name at -e line 1.
Execution of -e aborted due to compilation errors.
然而,为了保持它们的有用性,严格的vars允许在没有错误的情况下使用导入的变量。
$ perl -wE'use strict; say $Config{version};'
Global symbol "%Config" requires explicit package name at -e line 1.
Execution of -e aborted due to compilation errors.
$ perl -wE'use strict; use Config qw( %Config ); say $Config{version};'
5.18.1
use vars
只是创建一个新的变量并将其导出
虽然您的代码即将做到这一点,但它存在两个问题。
至关重要的是,在代码中遇到对变量的任何引用之前导入变量。需要做两个更改才能在代码中修复此问题。
赋值的操作数必须在计算该赋值之前进行编译,因此在代码引用变量之前,您的赋值不可能导入该变量。
*Package::foo = $Package::foo; # XXX Compile-time lookup *Package::foo = ${"Package::foo"}; # Runtime looup *Package::foo = ( my $anon ); # Would work too.
在导入变量之前,您需要等待整个脚本的编译,因此导入发生在strict已经禁止对变量的引用之后。您需要使用
BEGIN { }
[1]更快地执行导入。
对于要被视为已导入的变量,执行导出的代码必须在与要将变量导出到的包不同的包中编译。
如果我们应用这些修复,我们最终会得到以下结果:
$ perl -wE'
use strict;
BEGIN { package X; no strict qw( refs ); *main::x = ${"main::x"}; }
$x = 123; say $x;
'
123
注:
请记住
use Module qw( ... );
与基本相同
BEGIN { require Module; Module->import(qw( ... )); }
换句话说,在解析任何进一步的代码之前,执行模块并调用其
import
方法。