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

型グロブの代入

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

速くて汚い。existingFunctionこれにより、すべてのシンボルが にエイリアスされoldExistingFunctionます。これには、関心のあるサブルーチンが含まれますが、たまたま同じ名前を持つ可能性のあるスカラー、配列、ハッシュ、ハンドルも含まれます。

  • 利点: 何も考えずに、ただ機能するだけです。"素早い"
  • デメリット:「汚い」

コードリファレンスの割り当て

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

それはサブをエイリアスするだけです。これはまだパッケージ stash で行われているため、oldExistingFunctionシンボルはグローバルに表示されます。これは、必要な場合とそうでない場合があります。おそらくそうではありません。

  • 利点: エイリアシングが他の変数型に「漏れる」ことはありません。
  • 短所:より多くの思考、より多くのタイピング。*...{CODE} 構文を使用する場合は、さらに多くのことを考えます (個人的には、毎日使用するわけではありません)。

レキシカルコードリファレンス

my $oldFunction = \&ExistingClass::existingFunction;

Usingmyは、現在のブロック/ファイルにのみ表示される古い関数への参照を保持します。外部コードがあなたの助けなしにそれを手に入れる方法はもうありません。呼び出し規約に注意してください。

$self->$oldFunction(@args);
$oldFunction->($self, @args);
  • 利点: 視認性の問題がなくなりました
  • 短所:正解しにくい

ムース

jrockwayの回答を参照してください。グロブや参照をいじることはもうないので、それは正しい方法でなければなりませんが、それを説明するのに十分なことはわかりません。

于 2009-02-22T20:38:44.307 に答える
8

MooseまたはClass::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-syntaxを使用してそれについて気分が良くなる場合は、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 に答える