碰到这个小块……我想我已经知道了,但是看看是否有人可以阐明更多。
我的PERL5LIB
环境变量中有一个用于记录的模块。它在e:/Scripts/Log/Logger.pm
中。以下是摘录:
package Log::Logger;
...
package Log::NullLogger;
use base 'Log::Logger';
...
package Log::FileLogger;
use base 'Log::Logger';
...
package Log::DateFileLogger;
use base 'Log::FileLogger';
...
package LogTester;
use Data::Dump 'dump';
test() unless caller();
sub test {
warn dump \%INC;
...
}
我想对该模块进行一些更改,因此我将其复制到
e:/Test/Log/Log/Logger.pm
并开始进行更改和测试...我添加了一个新类并在Log::Logger
包中更改了一个继承的例程...package BasicFormatter;
...
但是我的测试很奇怪。一些新的代码正在使用,有些则没有。
%INC
的转储具有:"Log/Logger.pm" => "e:/Scripts/Log/Logger.pm"
...旧模块!据我所知,
use base 'Log::Logger'
出门并从Log/Logger.pm
重新加载PERL5LIB
,仅替换其中的那些软件包(即package BasicFormatter
来自新模块,但所有其他软件包均来自旧模块) )。我读到有关
use parent
的信息,当我用use base
替换use parent
时,表面上在use parent 'Log::FileLogger'
上出现编译错误,因为没有Log/FileLogger.pm
模块。 use base
从来没有抱怨过-我认为use parent
的弱点。我加了
use lib '..';
到模块顶部,并且所有内容都可以与
use base
一起使用,但这并不是我喜欢的解决方案,因为当我将其“发布”回e:/Scripts/Log/Logger.pm
时,它不会出现在最终模块中。使用use lib '..'
,现在显示%INC
"Log/Logger.pm" => "../Log/Logger.pm"
这是有道理的。
我的下一步是删除
use lib '..'
并将所有use base...
替换为our @ISA=(...)
。当我这样做时,代码开始起作用,并且%INC
根本没有显示Log/Logger.pm
的条目。请注意,当我在
e:/Test/Log/TestLogger.pl
中使用use lib '.';
在其中,它可以很好地拾取
e:/Test/Log/Log/Logger.pm
,并且use base
调用不需要重新打包。因此,我的结论是……当以模块化方式运行模块时,就Perl而言,模块未“加载”。因此,第一次尝试在该模块上执行
use base
的操作是require <module>
,然后从@INC
路径加载它,这可能会替换正在执行的modulino中已经存在的程序包。相反,使用@ISA
绕过对require
的调用,因此不会从@INC
加载模块。其他人对此有更多信息...将模块作为模块化模块进行测试不是一个好主意吗?
最佳答案
parent
要求您明确声明是要其实际加载父模块还是仅设置继承。这是优势,而不是劣势; base
的缺点是总是尝试加载模块,从而导致出现问题。
做:
use parent -norequire => 'Log::Logger';
...
use parent -norequire => 'Log::FileLogger';
等等
也就是说,如果您始终使用
base
或use
加载模块,则不会发生require
问题;如果您只是运行一个模块(例如perl Foo/Bar.pm
)或以其他方式加载它(use Test::Log::Logger
而不是use lib 'Test'; use Log::Logger
??),并且您的代码也尝试对该模块进行use
,则总是会冒被发现多个版本的风险。关于perl - @ISA vs使用基础vs使用父级,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/49279264/