我试图 猴子补丁 Perl 类:我想改变现有方法的行为。

perlmonks 上的这个节点 展示如何 添加 现有类的函数。我发现这种模式还可以用来为现有函数提供新的实现。

但是,我想知道如何调用原始函数。

我正在寻找这样的东西:

use ExistingClass;

# TODO: Somehow rename existingFunction() to oldExistingFunction().

sub ExistingClass::existingFunction {
    my $self = shift;

    # New behavior goes here.
    $self->oldExistingFunction(@_); # Call old behavior.
    # More new behavior here.
}
有帮助吗?

解决方案

类型团分配

*ExistingClass::oldExistingFunction = *ExistingClass::existingFunction;

又快又脏。这别名所有 existingFunction 符号到 oldExistingFunction. 。这包括您感兴趣的子项,还包括可能碰巧具有相同名称的任何标量、数组、散列、句柄。

  • 优点:无需思考,它就是有效的。“快的”
  • 缺点:“肮脏的”

代码引用分配

*ExistingClass::oldExistingFunction = \&ExistingClass::existingFunction;
# or something using *ExistingClass::symbol{CODE}

那只是子的别名。它仍然在包存储中完成,所以 oldExistingFunction 符号是全局可见的,这可能是也可能不是您想要的。可能不会。

  • 优点:别名不会“泄漏”到其他变量类型。
  • 缺点:多思考,多打字。如果使用 *...{CODE} 语法,需要更多思考(我个人并不是每天都使用它)

词汇代码参考

my $oldFunction = \&ExistingClass::existingFunction;

使用 my 保留对仅对当前块/文件可见的旧函数的引用。如果没有您的帮助,外部代码将无法再获取它。注意调用约定:

$self->$oldFunction(@args);
$oldFunction->($self, @args);
  • 优点:不再有可见性问题
  • 缺点:更难做对

驼鹿

杰罗威的回答. 。它必须是正确的方式,因为不再需要使用全局和/或引用,但我不知道它足以解释它。

其他提示

你应该使用 驼鹿 或者 类::方法::修饰符.

在这种情况下,你可以直接说:

around 'some_method' => sub {
    my ($orig, $self, @args) = @_;
    # ... before original ...
    $self->$orig(@_);
    # ... after original ...
};

除了其他答案之外,请查看以下模块:

我也在《动态语言》一章中谈到了这一点 掌握 Perl.

memoize的是一个很好的例子。

只需将其复制到词法变量并调用它。

my $existing_function_ref = \&ExistingClass::existingFunction;
*ExistingClass::existingFunction = sub { 
    my $self = shift;
    $self->go_and_do_some_stuff();
    my @returns = $existing_function_ref->( $self, @_ );
    $self->do_some_stuff_with_returns( @returns );
    return wantarray ? @returns : shift @returns;
};

如果你会觉得它更好地与面向对象的语法,你可以创建一个UNIVERSAL::apply方法(或任何基类您选择)。

sub UNIVERSAL::apply { 
    my ( $self, $block ) = splice( @_, 0, 2 );
    unshift @_, $self;
    goto &$block;
}

这样,你可以这样调用它:

my @returns = $self->apply( $existing_function_ref, @_ );

为了 驼鹿 类,你可以 按jrockway所说的去做;对于非 Moose 类,请执行以下操作:

use Class::MOP ();
use ExistingClass;

Class::MOP::Class->initialize('ExistingClass')->add_around_method_modifier(
    existingFunction => sub {
        my $orig = shift;

        # new behaviour goes here

        # call old behaviour
        my $result = $orig->(@_);

        # more new behaviour goes here
    }
);

作为备选,这有什么错:

package NewClass;
use base qw/ExistingClass/;

sub existingFunction {
# ....
}

sub oldExistingFunction {
    my $self = shift;
    return $self->SUPER::existingFunction(@_);
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top