当您运行perl -e "Bla->new"
时,您会收到以下众所周知的错误:
Can't locate object method "new" via package "Bla"
(perhaps you forgot to load "Bla"?)
由于我的监督,前几天发生在Perl服务器进程中。有多个脚本,其中大多数都有适当的use
语句。但是有一个脚本在{123}中的Bla->new
处进行了sub blub
但在顶部缺少use Bla
,当点击时没有任何其他脚本使用{ {1}}之前由服务器进程加载,然后爆炸!
单独测试脚本将是防止这一特定错误的明显方法,但唉,代码依赖于一个巨大的环境。你知道另一种防止这种疏忽的方法吗?
更新
以下是一个示例Bla
(尽管其优点)在Perl视图中的限制:
PPI
设置标题并指定use strict;
use HTTP::Request::Common;
my $req = GET 'http://www.example.com';
$req->headers->push_header( Bla => time );
my $au=Auweia->new;
__END__
PPI::Token::Symbol '$req'
PPI::Token::Operator '->'
PPI::Token::Word 'headers'
PPI::Token::Operator '->'
PPI::Token::Word 'push_header'
PPI::Token::Symbol '$au'
PPI::Token::Operator '='
PPI::Token::Word 'Auweia'
PPI::Token::Operator '->'
PPI::Token::Word 'new'
解析相同的内容。所以我不确定你如何在这样一个摇摇欲坠的基础上建立起来。我认为问题是Auweia->new
也可能是一个子程序; Auweia
直到运行时才能说出来。
进一步更新
好的,从@ Schwern下面的指导性评论中我了解到perl.exe
只是一个标记器,如果您接受其限制,可以构建它。
答案 0 :(得分:10)
测试是唯一值得付出努力的答案。如果代码包含忘记加载类的错误,则可能包含其他错误。无论遇到什么障碍,都要考验一下。否则你正在修补筛子。
那就是说,你有两种选择。您可以使用Class::Autouse,如果模块尚未加载,它将尝试加载模块。它很方便,但因为它会影响整个过程,所以会产生意想不到的效果。
或者您可以使用PPI扫描代码并查找所有类方法调用。 PPI::Dumper非常方便了解PPI如何看待Perl。
use strict;
use warnings;
use PPI;
use PPI::Dumper;
my $file = shift;
my $doc = PPI::Document->new($file);
# How PPI sees a class method call.
# PPI::Token::Word 'Class'
# PPI::Token::Operator '->'
# PPI::Token::Word 'method'
$doc->find( sub {
my($node, $class) = @_;
# First we want a word
return 0 unless $class->isa("PPI::Token::Word");
# It's not a class, it's actually a method call.
return 0 if $class->method_call;
my $class_name = $class->literal;
# Next to it is a -> operator
my $op = $class->snext_sibling or return 0;
return 0 unless $op->isa("PPI::Token::Operator") and $op->content eq '->';
# And then another word which PPI identifies as a method call.
my $method = $op->snext_sibling or return 0;
return 0 unless $method->isa("PPI::Token::Word") and $method->method_call;
my $method_name = $method->literal;
printf "$class->$method_name seen at %s line %d.\n", $file, $class->line_number;
});
答案 1 :(得分:0)
您没有说明您正在运行的服务器环境,但是从您所说的内容来看,您可以在执行任何单个页面之前预先加载所有模块。这不仅可以防止您描述的问题(每个脚本都必须记住加载它使用的所有模块),但它也可以节省您的内存。
在pre-forking服务器(通常与mod_perl和Apache一起使用)中,你真的想在第一次你的服务器之前加载尽可能多的代码,以便代码存储一次在copy-on-write共享内存中,而不是在每个子进程按需加载时多次。
有关在Apache中预加载的信息,请参阅Practical mod_perl
部分