在进行本地子程序调用时是否存在指定包名称的危险?

时间:2012-04-18 22:15:45

标签: perl

我继承了类似于下面显示的Perl代码。包中包含公共子例程,不导入也不导出命名空间。这种召集惯例似乎不典型。重构是一种选择。

我有兴趣了解在调用当前包中的子例程时显式命名包的风险/副作用。提前谢谢。

package Util;
sub _step1 {
    # <code>
}
sub _step2 {
    # <code>
}
sub doWork {
   Util::_step1();
   Util::_step2();
}
1;

2 个答案:

答案 0 :(得分:3)

有趣。我在想这会如何影响继承。

想象一下,Util类的子类会覆盖_step1_step2方法。如果该类调用dowork方法。它不会调用子类“_step1_step2方法,而是调用父类”_step1_step2方法。

附录

  

函数调用忽略继承。该模块需要执行类似于Util->; _step1()或 package - &gt; _step1()的继承才能实现,即使这样,包搜索也会从Util开始,而不是子类。 - Ven'Tatsu

真的?似乎很简单,可以测试。

我有两个软件包:我的程序中定义了Local::UtilLocal::Util::Child。 Local :: Util :: Child是Local::Util的子类。

Local::Util定义了以下构造函数和方法:

  • new:创建该类的新对象
  • _step1
  • _step2
  • doWork:这会使用_step1前缀调用_step2Util::
  • doWork2:这会在没有_step1前缀的情况下调用_step2Util::
  • doWork3:这会使用_step1前缀调用_step2__PACKAGE__
  • doWork4:这称为_step1_step2$class前缀取自ref

班级Local::Util::Child仅重新定义_step2方法。

以下是该计划:

#! /usr/bin/env perl
#
use strict;
use warnings;
use feature qw(say);

# This is our basic Local::Util object manipulation

my $util_obj = Local::Util->new;
say q("$util_obj" is a member of the ") . ref($util_obj) . q(" class);

print q($util_obj->_step1: );
$util_obj->_step1;

print q($util_obj->_step2: );
$util_obj->_step2;

# This is a child class object of the above

my $uc_obj = Local::Util::Child->new;
say q("$uc_obj" is a member of the ") . ref($uc_obj) . q(" class);

# Calls to straight forward methods

print q($uc_obj->_step1: );
$uc_obj->_step1;

print q($uc_obj->_step2: );
$uc_obj->_step2;

# Now calls to methods that call other methods

say qq(\n=====\$util_obj->doWork=====);
$util_obj->doWork;

say qq(\n=====\$uc_obj->doWork=====);
$uc_obj->doWork;

say qq(\n=====\$util_obj->doWork2=====);
$util_obj->doWork2;

say qq(\n=====\$uc_obj->doWork2=====);
$uc_obj->doWork2;

say qq(\n=====\$util_obj->doWork3=====);
$util_obj->doWork3;

say qq(\n=====\$uc_obj->doWork3=====);
$uc_obj->doWork3;

say qq(\n=====\$util_obj->doWork4=====);
$util_obj->doWork4;

say qq(\n=====\$uc_obj->doWork4=====);
$uc_obj->doWork4;

###################################################
# Package Local::Util
#
package Local::Util;

sub new {
    my $class = shift;
    my $self = {};
    bless $self, $class;
}

sub _step1 {
    say "I'm calling Local::Util::_step1";
}

sub _step2 {
    say "I'm calling Local::Util::_step2";
}

sub doWork {
    Local::Util::_step1();
    Local::Util::_step2();
}

sub doWork2 {
    _step1();
    _step2();
}

sub doWork3 {
    __PACKAGE__->_step1();
    __PACKAGE__->_step2();
}

sub doWork4 {
    my $self = shift;
    my $class = ref $self;

    $class->_step1();
    $class->_step2();
}
#
#############################################

#############################################
# Package Local::Util::Child
#

package Local::Util::Child;
use base qw(Local::Util);

sub _step2 {
    say "I'm calling Local::Util::Child::_step2";
}

而且,这是输出:

"$util_obj" is a member of the "Local::Util" class
$util_obj->_step1: I'm calling Local::Util::_step1
$util_obj->_step2: I'm calling Local::Util::_step2
"$uc_obj" is a member of the "Local::Util::Child" class
$uc_obj->_step1: I'm calling Local::Util::_step1
$uc_obj->_step2: I'm calling Local::Util::Child::_step2

=====$util_obj->doWork=====
I'm calling Local::Util::_step1
I'm calling Local::Util::_step2

=====$uc_obj->doWork=====
I'm calling Local::Util::_step1
I'm calling Local::Util::_step2

=====$util_obj->doWork2=====
I'm calling Local::Util::_step1
I'm calling Local::Util::_step2

=====$uc_obj->doWork2=====
I'm calling Local::Util::_step1
I'm calling Local::Util::_step2

=====$util_obj->doWork3=====
I'm calling Local::Util::_step1
I'm calling Local::Util::_step2

=====$uc_obj->doWork3=====
I'm calling Local::Util::_step1
I'm calling Local::Util::_step2

=====$util_obj->doWork4=====
I'm calling Local::Util::_step1
I'm calling Local::Util::_step2

=====$uc_obj->doWork4=====
I'm calling Local::Util::_step1
I'm calling Local::Util::Child::_step2

有趣。你是对的,我是否放置Util::前缀没有区别,它仍然调用父方法而不是子方法。放__PACKAGE__前缀的方法是一样的(我想你是怎么做的,以确保你调用当前类的定义)。我可以让孩子工作的唯一方法是使用我必须从$class命令获得的ref前缀。

所以,看起来如果你在另一个方法中调用一个方法,它将默认为该类的方法而不是子方法。我想这是有道理的 - 特别是因为它看起来像_step1_step2是私有方法,不应该在父方法之外访问。

答案 1 :(得分:0)

没关系。唯一的缺点是,如果重命名模块,可能会忘记重命名子调用。

但想做的事情很奇怪。如果你告诉我们你想要这样做的原因,我们或许可以提供更好的方法。