我有一个perl-mason文件,其中一行看起来像这样:
$result = PI::Membership::Service->cancel(name => $name)
这到底是什么意思?它在调用另一个模块吗?它是面向对象的perl代码吗?
感谢
它用三个参数调用(调用)子例程PI::Membership::Service::cancel
。
"PI::Membership::Service"
"name"
$name
给定正常的命名约定,这是在包PI::Membership::Service
中调用一个名为cancel
的子例程,该子例程在@INC
路径上的某个名为PI/Membership/Service.pm
的文件中定义(然而,有许多异常的命名约定),因此不能保证您会找到这样的文件。如果PI::Membership::Service
包(类)继承自一个或多个其他包,则cancel
子例程实际上可能在其中一个包中定义。
更多详细信息,请参阅perlobj
。
除非$result
是Pi::Membership::Service
对象,否则它实际上不是一个面向对象的调用,因为它既不是在创建也不是在操作对象。一个面向对象的调用看起来是这样的:
my $obj = Foo::Bar->new; #Creating an object of class `Foo::Bar`
$obj->Baz #Calling method "Baz" on object "$obj";
看起来这是一个对象样式的调用,用于访问另一个包中的子例程,该子例程尚未导出。
要了解实际情况,您必须了解命名空间。Perl使用命名空间。大多数时候,您可能没有意识到这一点,因为您使用的是main
的默认命名空间。名称空间是必需的,因为您可能会导致(尤其是在4.x之前的Perl版本中)函数和变量名称冲突。下面是我用旧的Perl3.x风格编写的一个程序:
require "fribulate.pl";
$value = 4.5;
$new_value = fribulate($value);
print "Fribulated Value = $new_value Original value = $valuen";
这是我的fribulate.pl
程序:
sub fribulate {
my $param = shift;
$value = $param * 2;
return $value * 6;
}
1;
当我运行程序时,我得到:
Fribulated Value = 54. Original Value = 9
等等?最初不是4.5吗?fribulate.pl
程序影响了我的$value
,因为它还使用了一个名为$value
的变量。为了解决这个问题,Perl创建了package
命令,该命令创建了一个新的名称空间:
package Fribulate;
sub fribulate {
my $param = shift;
$value = $param * 2;
return $value * 3.1416;
}
1;
现在,fribulate.pl
程序不在命名空间main
中,而是在命名空间Fribulate
中。因此,fribulate.pl
中使用的$value
变量与我的$value
变量不同。
但是,如果我在另一个名称空间中预先加上名称空间,我就可以访问它:
require "fribulate.pl";
$value = 4.5;
$new_value = fribulate($value);
print "Fribulated Value = $new_value Original value = $valuen";
# Printing the value of $value from frimbulate.pl:
print "And in fribulate.pl, it's using $Fribulate::valuen";
如果使用"文件:查找",您会看到此情况。要访问文件的全名,请使用$File::Find::name
。要访问文件的目录,请使用$File::Find::dir
。名称空间File::Find
是为File::Find
中的$dir
和$name
变量准备的。
名称空间的问题是,现在所有的东西都在新的名称空间中,包括我在frimbulate.pl
中的frimbulate
函数。因此,我的原始程序还必须在函数前面预先设置名称空间才能工作:
require "fribulate.pl";
$value = 4.5;
$new_value = Frimbulate::fribulate($value);
print "Fribulated Value = $new_value Original value = $valuen";
为了解决这个问题,你在frimbulate.pl
程序中做了一个小动作:
Package Frimbulate;
require Exporter;
@EXPORT = qw(frimbulate);
sub fribulate {
my $param = shift;
$value = $param * 2;
return $value * 3.1416;
}
1;
Exporter
包在@EXPORT
中的函数上撒上了魔法精灵尘1,并使它们可用于main
命名空间——所有内容所在的默认命名空间。因此,像File::Copy和File::Basename这样的模块使用Exporter
来访问它们各自的copy
和basename
子例程,而无需在它们前面预先准备包名。
这现在被认为是糟糕的样式,因为您可能会在没有任何警告的情况下覆盖具有相同名称的其他子例程。在编写模块的新样式中,您不再自动导出@EXPORT
数组中的所有函数。你会在File::Path中注意到这一点,它不会在没有我们明确请求的情况下自动将函数导出到main
命名空间。相反,你将它们放在@EXPORT_OK
中,这需要用户要求将它们推送到命名空间:
Frimbulate套餐
Package Frimbulate;
require Exporter;
@EXPORT_OK = qw(frimbulate); #You have to request the frimbulate subroutine
sub fribulate {
my $param = shift;
$value = $param * 2;
return $value * 3.1416;
}
1;
我的程序:
# Now I have to ask that the frimbulate subroutine be import into my main namespace
require "fribulate.pl" qw(frimbulate);
$value = 4.5;
$new_value = fribulate($value);
print "Fribulated Value = $new_value Original value = $valuen";
现在,这将为您提供足够的背景知识来阅读Perl模块文档,并很可能了解发生了什么。Perlmod文档涵盖了名称空间、符号表,甚至还有一些关于变量范围的内容。它包含了很多信息,如果没有基本信息,可能会有点吓人。
1使用Exporter模块时,没有像素受到伤害。如果查看使用perldoc -l Exporter
命令可以找到的Exporter.pm
,您会发现它直接操作符号表。