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
You can do runtime class modification using runkit. More specifically, you can use runkit_method_redefine.
As of PHP 5.6, there's still no support for monkey patching; however PHP 5.3 introduced anonymous functions. This answer is not exactly what you're looking for and could probably be improved upon, but the general idea is to use arrays, anonymous functions, and references to create a self-contained, self-referential array (an "object", if you will):
test.php
$inner = require('test2.php');
$inner['say'](); // Hi!
$inner['data']['say'] = 'Bye!';
$inner['say'](); // still says Hi!
$inner['set_say']('Bye!');
$inner['say'](); // Bye!
$inner = require('test2.php');
$inner['say'](); // Hi!
test2.php
$class = array(
'data' => array(
'say' => 'Hi!'
),
'say' => function() use (&$class){
echo $class['data']['say'].'<br />';
},
'set_say' => function($msg) use (&$class){
$class['data']['say'] =& $msg;
}
);
return $class;
Also, here's a disclaimer saying that the above code (along with monkey patching in PHP) is almost always a terrible idea, but there are times where this is absolutely necessary.
I have monkey-patched a class using eval() and namespaces. This may not be the answer for you, though, since this does not work if the class you are monkey-patching is already in a namespace. I haven't figured out how to get around that, other than trimming the namespace declaration from the eval string. However, doing so would likely break any namespace-dependent code within the class methods.
In my case, I am monkey-patching the core PDO class for unit-testing a class that depends on database interaction. But, maybe seeing my technique will help you figure out how to make it work for your situation.
I have the code snippets up in a blog post here: http://chrisgriffing.com/coding/php/2012/04/12/how-to-mock-pdo-and-other-objects/
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.
you probably already figured this out, but, just for reference, they are using stream wrappers,
http://php.net/manual/es/function.stream-wrapper-register.php
basically, they register an stream wrapper on file and phar, so when the code is loaded, thay can manipulate it, it doesnt work on code loaded from an opcache