4

我正在尝试修补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.
}
4

7 回答 7

10

Typeglob 赋值

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

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

  • 优点:不用思考,就行了。“快的”
  • 缺点:“脏”

代码引用分配

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

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

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

词法代码参考

my $oldFunction = \&ExistingClass::existingFunction;

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

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

驼鹿

请参阅jrockway 的答案。它必须是正确的方式,因为不再有 glob 和/或引用,但我不知道足以解释它。

于 2009-02-22T20:38:44.307 回答
8

您应该使用MooseClass::Method::Modifiers

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

around 'some_method' => sub {
    my ($orig, $self, @args) = @_;
    # ... before original ...
    $self->$orig(@_);
    # ... after original ...
};
于 2009-02-23T03:12:34.733 回答
4

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

我还在Mastering Perl的“动态语言”一章中谈到了这一点。

于 2009-02-23T18:50:52.480 回答
3

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

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;
};

如果您对 OO 语法感觉更好,您可以创建一个UNIVERSAL::apply方法(或在您选择的任何基类中)。

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

这样你就可以这样称呼它:

my @returns = $self->apply( $existing_function_ref, @_ );
于 2009-02-22T21:42:30.737 回答
2

Memoize就是一个很好的例子。

于 2009-02-22T20:45:58.813 回答
1

对于Moose课程,您可以按照 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
    }
);
于 2012-07-24T16:49:29.767 回答
-1

作为替代方案,有什么问题:

package NewClass;
use base qw/ExistingClass/;

sub existingFunction {
# ....
}

sub oldExistingFunction {
    my $self = shift;
    return $self->SUPER::existingFunction(@_);
}
于 2009-02-22T21:12:37.237 回答