Search code examples
perlmonkeypatching

How do I access the original method of a monkeypatched method in Perl?


I'm trying to monkey patch a Perl class: I want to change the behavior of an existing method.

This node on perlmonks shows how to add a function to an existing class. I found that this pattern can also be used to provide a new implementation for an existing function.

However, I'd like to know how to call the original function.

I'm looking for something like this:

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

Solution

  • Typeglob assignment

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

    Quick and dirty. This aliases all existingFunction symbols to oldExistingFunction. This includes the sub you're interested in, but also any scalars, arrays, hashes, handles that might happen to have the same name.

    • Advantages: no thinking, it just works. "quick"
    • Disadvantages: "dirty"

    Coderef assignment

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

    That one only aliases the sub. It's still done in the package stash, so the oldExistingFunction symbol is globally visible, which might or might not be what you want. Probably not.

    • Advantages: that aliasing doesn't 'leak' to other variable types.
    • Disadvantages: more thinking, more typing. A lot more thinking if going for the *...{CODE} syntax (I personnally don't use it every day)

    Lexical coderef

    my $oldFunction = \&ExistingClass::existingFunction;
    

    Using my keeps a reference to the old function that is only visible to the currrent block/file. There is no way for external code to get hold of it without your help anymore. Mind the calling convention:

    $self->$oldFunction(@args);
    $oldFunction->($self, @args);
    
    • Advantages: no visibility issues anymore
    • Disadvantages: harder to get right

    Moose

    See jrockway's answer. It's got to be The Right Way, since there's no mucking around with globs and/or references anymore, but I don't know it enough to explain it.