Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

monkey patching in php

I'm trying to figure out how monkey patching works and how I can make it work on my own objects/methods.

I've been looking at this lib, it does exactly what I want to do myself: https://github.com/antecedent/patchwork

With it you can redefine a method from an object. It uses the 'monkey patch' technique for that. But I couldn't really figure out what exactly is going on by looking at the source.

So suppose I have the following object:

//file: MyClass.php
namespace MyClass;

class MyClass {

    public function say()
    {
        echo 'Hi';
    }
}

I'd like to do something like this:

Monkeypatch\replace('MyClass', 'say', function() {
    echo 'Hello';
});

$obj = new MyClass();
$obj->say();  // Prints: 'Hello'

But i'm not sure how to code the actual patching part. I know namespaces in this context are important. But how does that exactly let me patch a certain method? And do I need to use eval() somewhere (if so, how)?

I couldn't really find any good examples about this matter, except: http://till.klampaeckel.de/blog/archives/105-Monkey-patching-in-PHP.html

But I really don't see how I can apply that to my own objects/methods. I'm hoping for a good explanation or example.

like image 831
w00 Avatar asked Apr 08 '12 18:04

w00


2 Answers

You can do runtime class modification using runkit. More specifically, you can use runkit_method_redefine.

like image 87
tabdulla Avatar answered Oct 06 '22 03:10

tabdulla


In the case of http://till.klampaeckel.de/blog/archives/105-Monkey-patching-in-PHP.html what actually makes the difference is the \ character used in front of the second strlen.

When you are using namespaces you can either use a namespace and directly invoke the methods/classes declared in the namespace:

use TheNamespace;
$var = new TheClass();

Or invoke the class explicitly by using something like:

$var = new \TheNamespace\TheClass();

So by invoking \strlen() instead of strlen() you are explicitly requesting PHP to use the default strlen and not the strlen defined for this namespace.

As for monkey patching you could use runkit (http://ca.php.net/runkit). Also with regards to patchwork there are a fair amount of examples in their website (http://antecedent.github.com/patchwork/docs/examples.html). You could check the magic method example that is replacing a function in a class.

like image 23
mobius Avatar answered Oct 06 '22 04:10

mobius