我有一个有趣的情况。在一些(大型)遗留代码中,有一个名称空间应该看起来像require A::B
,但是添加了A的路径,因此可以只说require B
。但是,我希望能够使用这两种调用。这是否可以在不创建重定向包的情况下实现?例如,有没有办法双重声明一个包?
谢谢!
答案 0 :(得分:16)
首先加载包:
require A::B;
然后将B
别名改为A::B
:
*B:: = *A::B::;
然后告诉require
它已加载B
$INC{'B.pm'}++;
为了确保一切正常,最好在BEGIN
块内执行这些操作:
BEGIN {
require A::B;
*B:: = *A::B::;
$INC{'B.pm'}++;
}
在此之后,所有require A::B;
和require B;
行都将变为无操作。您还可以使用任一名称引用该包中的变量。 \&A::B::foo == \&B::foo
为了使透明工作,您可以将以下代码添加到每个文件中:
A/B.pm
*B:: = *A::B::;
$INC{'B.pm'}++;
B.pm
*A::B:: = *B::;
$INC{'A/B.pm'}++;
然后,如果用户require A::B;
,他们可以致电A::B::foo
或B::foo
,require B;
将成为无操作。
如果用户require B;
,他们可以致电A::B::foo
或B::foo
,require A::B;
将成为无操作。
但是为了可维护性,最好将所有实际代码保存在一个文件中(连同上面的别名代码),并将另一个文件设置为仅加载真实文件的填充程序。假设A/B.pm
包含真实代码:
A/B.pm
*B:: = *A::B::; # this gets added to the existing file
$INC{'B.pm'}++;
B.pm
require A::B; # this is the entire file
答案 1 :(得分:2)
require Something
将在@INC
中的目录中搜索名为Something.pm
的文件。
要让some-path/A/B.pm
加载require B
或require A::B
,您需要在some-path
目录列表中同时包含some-path/A
和@INC
有many many ways添加目录或以其他方式操纵您的@INC
列表。
答案 2 :(得分:1)
Eric的解决方案可行,但说实话,我会拍摄任何在真实生产代码中执行此操作的人。您可以通过使用Package::Stash中的方法获得类似的结果,但同样,为什么要像这样弄乱符号表呢?我宁愿修复那些调用错误方式的遗留代码。说真的,对代码进行搜索和替换以及修改软件包名称有多难?
让require B;
实际找到包A :: B的另一个快速而简单的方法是简单地在lib /目录中创建指向A / B.pm的符号链接:
cd lib
ln -sf -T A/B.pm B.pm
请注意,这将创建具有相同代码的两个包,因此一个中的变量不与另一个相同:$A::B::foo
将完全相同即使它们的声明来自同一个文件,也要与$B::foo
分开。