从间接包含的模块中命名空间污染

时间:2015-06-30 14:43:05

标签: perl

考虑以下脚本p.pl

use strict;
use warnings;

use AA;

BB::bfunc();

文件AA.pm是:

package AA;

use BB;
1;

,文件BB.pm为:

package BB;

sub bfunc {
    print "Running bfunc..\n";
}
1;

运行p.pl会输出(没有警告或错误):

Running bfunc..

问:即使BB::bfunc()中没有p.pl,为什么可以从use BB;致电p.pl?这个奇怪的行为不是吗?或者是否存在可能有用的情况?

(对我来说,似乎这种行为只会向另一个软件包泄露信息并违反数据隐藏原则。导致难以维护的程序..)

2 个答案:

答案 0 :(得分:3)

虽然最好是userequire您计划访问的每个依赖项(试图避免在此处使用),但您不必这样做

只要您使用完整的包名称,就可以了。重要的是Perl知道名称空间。如果没有,它将失败。

当你use时,这相当于:

BEGIN {
  require Foo::Bar;
  Foo::Bar->import();
}

require将使用Foo::Bar并根据操作系统的约定将其转换为路径。在Linux上,它会尝试在Foo/Bar.pm内的某处找到@INC。然后它将加载该文件并在%INC中记下它加载文件。

现在Perl知道该命名空间。如果是use,它可能会import进入您自己的命名空间。但只要你使用全名,它就会随时随地可用。同样地,您在主script.pl中拥有的内容可以通过说main::frobnicate()在包内找到。 (请不要那样做!)

在一个.pm模块文件中捆绑多个名称空间/包也并不罕见。 CPAN上有很多大牌,就像XML::Twig一样。

如果你这样做,并且不导入任何东西,获取不同名称空间下的东西的唯一方法是使用全名。

如您所见,这根本不是污染。

答案 1 :(得分:3)

您没有污染命名空间,因为BB中的函数未被“导入”到您现有的命名空间中。

它们是分开的,可以自主引用。

如果您正在制作模块,那么通常您会通过Exporter两个列表进行定义:

@EXPORT@EXPORT_OK

前者是您use包时导入的内容列表。后者是您可以通过以下方式明确导入的内容:

use MyPackage qw ( some_func ); 

您还可以通过package在本地命名空间中定义our个变量,并通过$main引用它们。

 our $fish = "haddock";
 print $main::fish;

执行此操作时,您将明确引用main命名空间。当您use某个模块时,您需要perl去寻找它,并将其包含在%INC中。然后我'知道'那个命名空间 - 因为它必须为了解决依赖关系。

但这不是名称空间污染,因为在您提出要求之前,它不会在您的命名空间中包含任何内容。

如果在同一程序中有多个包,这可能会更有意义:

use strict;
use warnings;

package CC;

our $package_var = "Blong";

sub do_something {
   print $package_var,"\n"; 
}

package main;

use Data::Dumper;
our $package_var = "flonk";
print Dumper $package_var;
print Dumper $CC::package_var;

每个package都是它自己的命名空间,但是你可以在另一个中“捅”东西。 perl也可以通过对象实现这一点 - 实例化对象的内部或实际上“修补”它们。

这是非常强大的,但我通常建议真的不好的风格。