让我们说,我们的框架有两个模块: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
Queries.pm加载发生在check_module_queries(Eludia.pm的BEGIN {}),
使用Loader.pm(通过use Loader.pm <params>
)为每个请求加载
答案 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
的开头添加一些调试打印。