Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

modify a method/function at runtime

Tags:

php

reflection

I've been looking at the php reflection methods, what i want to do is inject some code after the method is opened and before any return value, for example i want to change:

function foo($bar)
{
    $foo = $bar ;
    return $foo ;
}

And inject some code into it like:

function foo($bar)
{
    //some code here
    $foo = $bar ;
    //some code here
    return $foo ;
}

possible?

like image 518
mononym Avatar asked May 28 '10 18:05

mononym


2 Answers

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 methods to be prefixed with an '_' for this to work... (or you can chose another prefix option, or you can just scope them all protected)...

like image 84
ircmaxell Avatar answered Sep 30 '22 00:09

ircmaxell


Look into anonymous functions. If you can run PHP 5.3 that might be more along the lines of what you're trying to do.

like image 23
Jarrod Nettles Avatar answered Sep 30 '22 00:09

Jarrod Nettles