我有一个 perl mason 文件,其中一行如下所示:
$result = PI::Membership::Service->cancel(name => $name)
这到底是什么意思呢?它是在调用另一个模块吗?它是面向对象的 perl 代码吗?
谢谢
它PI::Membership::Service::cancel
使用三个参数调用(调用)子例程。
"PI::Membership::Service"
"name"
$name
给定正常的命名约定,这是调用cancel
在 package中调用的子例程PI::Membership::Service
,定义在PI/Membership/Service.pm
沿路径某处命名的文件中@INC
(但是有许多不正常的命名约定,因此不能保证您会找到这样的文件)。如果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
. 命名空间是必需的,因为您最终可能会(尤其是在 Perl 的 4.x 之前的版本中)函数和变量名称冲突。这是我用旧的 Perl 3.x 风格编写的程序:
require "fribulate.pl";
$value = 4.5;
$new_value = fribulate($value);
print "Fribulated Value = $new_value Original value = $value\n";
这是我的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
中。因此,其中$value
使用的变量fribulate.pl
与我的$value
变量不同。
但是,如果我在其前面加上命名空间,我可以访问另一个命名空间中的变量:
require "fribulate.pl";
$value = 4.5;
$new_value = fribulate($value);
print "Fribulated Value = $new_value Original value = $value\n";
# Printing the value of $value from frimbulate.pl:
print "And in fribulate.pl, it's using $Fribulate::value\n";
如果您使用File:Find,您会看到这一点。要访问文件的全名,请使用$File::Find::name
. 要访问文件的目录,请使用$File::Find::dir
. 命名空间File::Find
被添加$dir
到.$name
File::Find
命名空间的问题是现在所有东西都在新的命名空间中,包括我frimbulate
在frimbulate.pl
. 因此,我的原始程序还必须在函数前面添加命名空间才能工作:
require "fribulate.pl";
$value = 4.5;
$new_value = Frimbulate::fribulate($value);
print "Fribulated Value = $new_value Original value = $value\n";
为了解决这个问题,你在frimbulate.pl
程序中做了一些花哨的步法:
Package Frimbulate;
require Exporter;
@EXPORT = qw(frimbulate);
sub fribulate {
my $param = shift;
$value = $param * 2;
return $value * 3.1416;
}
1;
该Exporter
包将魔法精灵灰尘1洒在其中的函数上@EXPORT
,并使它们可用于main
命名空间——所有东西所在的默认命名空间。因此,像File::Copy和File::Basename这样的模块用于Exporter
允许您访问它们各自copy
的basename
子例程,而无需在它们前面添加包名。
这现在被认为是不好的样式,因为您最终可能会在没有任何警告的情况下覆盖具有相同名称的其他子例程。在新的编写模块风格中,您不再自动导出@EXPORT
数组中的所有函数。您会在File::Path中注意到这一点,它不会在main
没有我们明确请求的情况下自动将其函数导出到命名空间中。相反,您将它们放入@EXPORT_OK
需要用户要求将它们推送到命名空间中:
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 = $value\n";
现在,这应该为您提供足够的背景来阅读Perl 模块文档,并且很可能了解发生了什么。Perlmod 文档涵盖了名称空间、符号表,甚至还有一些关于变量范围的内容。它包含很多信息,如果没有基本信息可能会有点吓人。
1使用 Exporter 模块时没有任何小精灵受到伤害。如果您查看Exporter.pm
可以使用该perldoc -l Exporter
命令找到的内容,您会发现它正在直接操作符号表。