perl:函数名冲突

时间:2011-12-26 08:41:53

标签: perl module

让我们说,我们的框架有两个模块:Handler.pm和Queries.pm

Queries.pm是可选的,正在fastcgi进程启动时加载

BEGIN {
&{"check_module_$_"}        () foreach (Queries);

}

sub check_module_queries {
...
    require Eludia::Content::Queries;
...
}

每个模块函数都加载在一个公共名称空间

现在,在Handler.pm和Queries.pm中有两个具有相同名称(setup_page_content)的函数

在Handler.pm

中调用setup_page_content

看起来原始作者建议每当加载Queries.pm时都会调用Queries.pm:setup_page_content

有时它不会发生:在这些情况下,追溯(通过调用者()获得)表明,setup_page_content是从模块Handler.pm调用的。

我在调用之前记录了%INC,它包含Queries.pm,在这些情况下它是完整路径

此行为不一致,并且在2-3%的生产安装尝试中弹出,主要是当我发送两个并行相同的http请求时。由于重现的努力程度,我还没有确定它是否是特定于安装的。

如何决定将调用哪个版本的同名函数?

这是明确定义的行为吗?

应该有原因,原作者以这种方式编写代码

更新

perl版本为v5.10.1 built for x86_64-linux-gnu-thread-multi

更新2

代码:Handler.pmQueries.pm

Queries.pm加载发生在check_module_queries(Eludia.pm的BEGIN {}),

使用Loader.pm(通过use Loader.pm <params>

为每个请求加载

4 个答案:

答案 0 :(得分:5)

每当加载Custom.pm时,我都想调用Custom.pm:setup_page_content

所以,您希望在Custom::setup_page_content存在时致电。

if (exists(&Custom::setup_page_content)) {
   Custom::setup_page_content(...);
} else {
   Handler::setup_page_content(...);
}

有时它不会发生。

完全没有关于此的信息使我无法发表评论。码?什么?


有没有办法'卸载'模块但是把它留在%INC?

加载模块只是运行它。你不能“取消”代码。充其量,您可以手动撤消运行它的一些效果。这是否包括更改%INC完全取决于您。

答案 1 :(得分:4)

当存在名称空间冲突时,最近定义/加载的函数将优先。

答案 2 :(得分:2)

这些不是合适的模块。这些只是库。如果将它们转换为具有适当名称间距的适当模块,则不会出现此问题。你几乎不需要做任何事情:

包查询;

sub new {

my $proto = shift;
my $class = ref($proto) || $proto;
my $self = {};

bless ( $self, $class );

return $self;

}

你会很顺利的。当然,您的程序需要进行一些更改才能实际访问类函数。您可以查看导出到函数以节省一些重构时间。

我已经在github上分叉了代码并发起了一个pull请求,希望能解决你的问题。

答案 3 :(得分:0)

行为是完美定义的:当您调用PACKAGENAME :: function_name时,将调用PACKAGENAME :: function_name。它当时不能超过一个PACKAGENAME :: function_name。

可以根据需要多次重新定义每个功能。比如说,执行像

这样的代码
eval "sub PACKAGENAME::function_name {...}";

该函数被[重新]定义。当您require某个.pm文件时,它与eval字符串及其内容非常相似。

如果未明确定义PACKAGENAME,则使用__PACKAGE__值。

因此,如果您注意setup_page_content的版本取自Handler.pm,则必须表明Handler.pm的内容已被执行(use {{1}加载require后(最后一次)。},read / eval等)。

因此,您必须跟踪Queries.pm加载的所有事件。简单的方法是在Handler.pm的开头添加一些调试打印。