首页 > 解决方案 > new SomeModule::SomeName vs SomeModule::SomeName->new(),有什么区别?

问题描述

我对 perl 很陌生,所以你必须原谅我的无知。

我正在做一个遗留项目。我没有专用的 IDE,我使用的是带有专用 Perl 插件的 PHPStorm。将鼠标悬停在new关键字上时,我收到警告Using of fancy calls is not recommended, use TCO::AEMAP->new()

有问题的代码是

my $aemapper = new TCO::AEMAP();

基本上它建议做

my $aemapper = TCO::AEMAP->new();

这种说法有什么优点,还是仅仅是一种约定?我在谷歌上找不到很多东西,因为我不确定要找什么。

标签: perl

解决方案


new Foo版本称为间接对象语法。这是在包上调用构造函数的老式方式,在现代 Perl 中不鼓励这样做。这是perldoc 中相关部分的部分引用。

出于多种原因,我们建议您避免使用此语法。

首先,阅读起来可能会令人困惑。在上面的示例中,尚不清楚 save 是由 File 类提供的方法,还是只是一个期望文件对象作为其第一个参数的子例程。

当与类方法一起使用时,问题更加严重。因为 Perl 允许将子例程名称写成裸字,所以 Perl 必须猜测方法后面的裸字是类名还是子例程名。换句话说,Perl 可以将语法解析为 File->new( $path, $data ) 或 new( File( $path, $data ) ) 。

为了解析这段代码,Perl 使用启发式算法,基于它所看到的包名、当前包中存在的子例程、之前看到的裸词以及其他输入。不用说,启发式可以产生非常令人惊讶的结果!

较早的文档(和一些 CPAN 模块)鼓励使用这种语法,特别是对于构造函数,因此您可能仍然会在野外找到它。但是,我们鼓励您避免在新代码中使用它。

另一种方法是在带有箭头的包上new作为类方法调用,如Foo->new. 箭头->做了三件事:

  1. 它查找左侧的内容。在这种情况下,barewordFoo看起来像一个包名。因此 Perl 将查看它是否知道具有该名称的包(或命名空间)。
  2. 它调用刚刚找到的包中箭头右侧的方法。
  3. 它传入右边的东西,在我们的例子中是Foo包名,作为第一个参数。这就是为什么在方法声明中您会看到my ($class, @args) = @_或类似的原因。

对于所有其他面向对象的调用,通常使用箭头语法。但是周围有很多使用间接对象语法的旧代码new,尤其是 CPAN 上的旧模​​块仍然在其文档中使用它。

两者都有效,但不鼓励使用间接对象语法。用于Foo->new新代码。


推荐阅读