Well, one way, would be to make all the method calls "virtual":
class Foo {
protected $overrides = array();
public function __call($func, $args) {
$func = strtolower($func);
if (isset($this->overrides[$func])) {
// We have a override for this method, call it instead!
array_unshift($args, $this); //Add the object to the argument list as the first
return call_user_func_array($this->overrides[$func], $args);
} elseif (is_callable(array($this, '_' . $func))) {
// Call an "internal" version
return call_user_func_array(array($this, '_' . $func), $args);
} else {
throw new BadMethodCallException('Method '.$func.' Does Not Exist');
}
}
public function addOverride($name, $callback) {
$this->overrides[strtolower($name)] = $callback;
}
public function _doSomething($foo) {
echo "Foo: ". $foo;
}
}
$foo = new Foo();
$foo->doSomething('test'); // Foo: test
PHP 5.2:
$f = create_function('$obj, $str', 'echo "Bar: " . $obj->_doSomething($str) . " Baz";');
PHP 5.3:
$f = function($obj, $str) {
echo "Bar: " . $obj->_doSomething($str) . " Baz";
}
All PHP:
$foo->addOverride('doSomething', $f);
$foo->doSomething('test'); // Bar: Foo: test Baz
It passes the instance of the object as the first method to the "override". Note: This "overriden" method will not have access to any protected members of the class. So use getters (__get
, __set
). It WILL have access to protected methods, since the actual call is coming from __call()
...
Note: You'll need to modify all your default methdos to be prefixed with an '_' for this to work... (or you can chose another prefix option, or you can just scope them all protected)...