- 论坛徽章:
- 0
|
[quote]原帖由 [i]neil_young[/i] 于 2005-11-22 13:43 发表
我用的是Apache+perl 做的web管理系统,现在碰到几个让我迷惑的事情。
我要在一个pl文件,或者说是那种包内部申明一个私用的包内全局变量。
我举个例子,只是示意,PrintToPage函数是个假定输出到HTML页面上显示 ... [/quote]
从你的问题看,应该可确认你的script运行在mod_perl下。mod_perl与普通cgi最大的不同是,运行在mod_perl下的script只编译一次就被储藏在apache进程里,并继续server后续请求。
另外,一般mod_perl下的脚本都会被相应的Handler进行封装,变成一个包。例如,如果你这里的script运行在Apache::Register下,那它就会被封装在一个package里,这个package只有一个函数,叫做handle(),你的script实际上被wraped在这个handle()函数里。这样,你的script里的子函数changea,实际上就变成了handle()的内嵌子函数。
然后,你的changea子函数使用的变量$a是在子函数之外申明的,这在mod_cgi下不会有什么问题,然而在mod_perl下,这就会造成一个closure。也就是说,changea()里的$a,实际上是外围的my $a的私有拷贝,然而从这一刻起,它就脱离了外围的my申明的变量作用域,看起来就跟一个全局变量一样。
为什么会造成closure?原因就是前面偶提的:一是你的script只编译一次,就储藏在apache进程里;二是你的script实际被wraped成一个package,package里的子函数会通过symbol table的形式export出去,export出去的符号当然不会被原始package里的my申明来初始化。
如果还不明白,可引用programming perl里的example来看看:
sub make_saying {
my $salute = shift;
my $newfunc = sub {
my $target = shift;
print "$salute, $target!n";
};
return $newfunc;
}
上面的return返回一个匿名函数,这个匿名函数使用了函数外my申明的变量,它实际上是个closure。
$f = make_saying("Howdy");
初始化,这个过程就相当于你的script在mod_perl下编译的过程。$f就相当于export出来的符号。
然后,不管你怎样访问$f,例如:
$f->("world");
$f->("test");
...
$salute都不会再初始化了,它看起来就跟一个全局变量一样。
当然,如果你再次$g = make_saying("Welcome"); 这等于是重新编译了一次mod_perl脚本,这个符号就改变了。
所以,你的这个子函数:
sub changea
{
PrintToPage "函数内:",$a;
$a=2;
}
从它运行的第一次起,它里面的$a就与外部的my $a脱离了哦,第二次运行时,它会记住上一次的值(因为编译后的code驻留在apache进程里),并且不会被外部的my来初始化了。
讲了这么多,不知你是否明白?偶们的mod_cgi迁移到mod_perl下时,也是经历了好多这样的问题。
解决你这个问题的方法有3个,一是把变量当参数传递,例如:
my $a=1;
changea(1);
sub changea
{
my $a=shift;
$a+1;
}
或者用our来申明一个全局的package变量:
our $a=1;
changea();
sub changea
{
$a+1;
}
或者把你的script定义成package,然后在主script里use或require这个package,这样也可避免问题。 |
|