我正在尝试monkey patch一个Perl类:我想改变现有方法的行为。
This node on 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.
}
答案 0 :(得分:10)
*ExistingClass::oldExistingFunction = *ExistingClass::existingFunction;
快速而肮脏。这会将所有existingFunction
符号别名化为oldExistingFunction
。这包括您感兴趣的子,以及可能碰巧具有相同名称的任何标量,数组,哈希,句柄。
*ExistingClass::oldExistingFunction = \&ExistingClass::existingFunction;
# or something using *ExistingClass::symbol{CODE}
那个只对别名别名。它仍然在软件包存储中完成,因此oldExistingFunction
符号是全局可见的,可能是也可能不是你想要的。可能不是。
my $oldFunction = \&ExistingClass::existingFunction;
使用my
保留对仅对当前块/文件可见的旧函数的引用。没有你的帮助,外部代码无法掌握它。注意召唤惯例:
$self->$oldFunction(@args);
$oldFunction->($self, @args);
见jrockway's answer。它必须是正确的方式,因为不再有使用globs和/或引用的杂乱,但我不知道它足以解释它。
答案 1 :(得分:8)
您应该使用Moose或Class::Method::Modifiers。
在这种情况下,你可以说:
around 'some_method' => sub {
my ($orig, $self, @args) = @_;
# ... before original ...
$self->$orig(@_);
# ... after original ...
};
答案 2 :(得分:4)
答案 3 :(得分:2)
Memoize就是一个很好的例子。
答案 4 :(得分:2)
只需将其复制到词法变量并调用它即可。
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, @_ );
答案 5 :(得分:1)
对于Moose课程,您可以do what jrockway says;对于非驼鹿班,请执行以下操作:
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
}
);
答案 6 :(得分:-1)
作为替代品,有什么问题:
package NewClass;
use base qw/ExistingClass/;
sub existingFunction {
# ....
}
sub oldExistingFunction {
my $self = shift;
return $self->SUPER::existingFunction(@_);
}