tags:

views:

61

answers:

5

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?

+1  A: 

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.

Jarrod
+1  A: 

This isn't possible, at least not in the way you are after. As the comment suggested, reflection is for getting information about classes/functions, not modifying them.

There is a PHP extension called Runkit which I believe provides this type of functionality - http://www.php.net/manual/en/book.runkit.php, however this isn't going to be installed by default on the vast majority of hosts out there.

There may be a different way of doing this though. Perhaps if you could give some more info on what you're trying to do, and why you can't modify the function in question, we might be able to provide some pointers. E.g. is the function you want to modify a core PHP function, or code in a third party library which you don't want to edit?

Tim Fountain
+2  A: 

Just an idea:

function foo($bar, $preprocess, $postprocess){

    //IF CONDITION($preprocess)
    include('/mylogic/'.$preprocess.".php"); //do some preprocessing here?
    $foo = $bar ;
    //IF CONDITION($postprocess)
    include('/mylogic/'.$postprocess.".php"); //process $foo here?
    //FINALLY return
    return $foo;

}
andreas
Good idea... though i'd probably make $preprocess and $postprocess into callbacks ('functionname' or array('classname','methodname')) and use call_user_func to call them. it would have scoping implications, but that would also make it safer IMHO.
grossvogel
it needs to be done for all methods in my application, and i want it to remain clean
mononym
A: 

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)...

ircmaxell
A: 

Maybe I'm missing something, but do you really want to "inject" code as you say? What are you trying to achieve? If you simply want to execute one block of code when A happens, and another when B happens, then all you need is simple programming logic, like an if() statement.

Are you really trying to alter a function at runtime? Or is this just a logic problem?

Be more specific about what you need to do.

Logic Artist