Is it possible to rename a class method in PHP 5.2 during run time? Is it possible to do that using Reflection?
Given:
class Test
{
public function myMethod()
{
echo 'in my method';
}
}
I want to be able to rename myMethod()
to oldMethod()
so that later I do this:
$test = new Test();
$test->oldMethod(); // in my method
$test->myMethod(); // run time error: method does not exist
From comment below question:
because I would like to install call event handlers on classes, without the classes knowing about it, so I would know that the user is calling a method from a class before that method is actually called.
Solution: use a Decorator.
class EventDecorator
{
protected $_instance;
public function __construct($instance)
{
$this->_instance = $instance;
}
public function __get($prop)
{
printf('Getting %s in %s', $prop, get_class($this->_instance));
return $this->_instance->$prop;
}
public function __set($prop, $val)
{
printf('Setting %s with %s in %s',
$prop, $val, get_class($this->_instance));
return $this->_instance->$prop = $val;
}
public function __call($method, $args)
{
printf('Calling %s with %s in %s',
$method, var_export($args, TRUE), get_class($this->_instance));
return call_user_func_array(array($this->_instance, $method), $args);
}
}
Then you can wrap any class into it:
class Foo
{
public $prop;
public function doSomething() {}
}
$foo = new EventDecorator(new Foo);
$foo->prop = 'bar'; // Setting prop with bar in Foo
$foo->prop; // Getting prop in Foo
$foo->doSomething('something');
// Calling doSomething with array (0 => 'something',) in Foo
This can be fleshed out to provide pre and post hooks. You could also make the Decorator use the Subject/Observer Pattern and fire events to whatever other object registered to the decorator. The above approach is more maintainable and understandable than monkeypatching random methods with runkit.
Additional notes:
- You might be interested in the Symfonys EventDispatcher component.
- If you are after Aspect Oriented programming, read http://sebastian-bergmann.de/archives/573-Current-State-of-AOP-for-PHP.html - it's from 2006 but there is not much changed in that field since then.
- If you are after horizontal reuse, you will like PHP's Trait functionality that is supposed to be in one of the next few versions.
Using Runkits runkit_method_rename you can do this.
For all of you who are asking why you would need this, I have an idea that is very similar. My idea is to attempt to rename an entire PHP Class on the fly. It would be used, in my case, for an IRC Chat bot that I would have load and instantiate plugins on the fly, so that I would no need to reboot the bot and uptime would be very long. This would include renaming of pre-loaded classes of the same name as the class I would be attempting to load, so that there would be no conflict and it would run properly.
For example:
I have $bot
running on irc.example.com
I have the plugin test.php installed and working, now when this is loaded into memory I can alter the file test.php without any change to $bot
So I update test.php
Now I want to cause it to load into $bot
, but $bot
already has a test load in it, and it would conflict if I attempted to include test.php again
so instead, we run a rename function to rename class test to class test[sha1 of a counter]
and then we include 'test.php'
$bot->test = new test();
and there we have it, an updated test plugin installed and loaded into memory on $bot
with no reboot.
This is all theory, but it's something to think about before instantly flaming someone for their ideas with the "Why would you even need this" attitude.
I mean, let's be honest here. What are the odds that you're a super genius who knows everything there is to know about programming and would know what everyone would or wouldn't need?