碰到这个小块……我想我已经知道了,但是看看是否有人可以阐明更多。

我的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';


等等

也就是说,如果您始终使用baseuse加载模块,则不会发生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/

10-14 19:49