开发者

Getting $this inside function

开发者 https://www.devze.com 2023-03-30 20:07 出处:网络
I have a function outside of my class, and i\'m calling it from inside using call_user_func, my problem is that i cant access class inside the function. i need a way to access my class without passing

I have a function outside of my class, and i'm calling it from inside using call_user_func, my problem is that i cant access class inside the function. i need a way to access my class without passing it in arguments, if there开发者_StackOverflow社区 was a way to make $this work inside the function that would be wonderful.

Any advice other than passing class with argument into function will be appreciated;

function test($arg1)
{
    $this->code = 10; // i know $this won't work here, 
                       // but i need a way to change $code 
                       // property from this function without 
                       // passing class into this function by using arguments
}

class MyClass
{
    public $code;
    public function call()
    {
         call_user_func("test", "argument1");
    }
}


If you can move the function inside of your class, you would be able to call it like this:

call_user_func(array($this, 'the_function'));

If you have PHP5.3, you can use a closure:

$that = $this;
$function = function() use ($that) {
    // use $that instead of $this
};
call_user_func($function);

If you could add an argument, you could do this:

call_user_func('the_function', "argument1", $this);

Pass $this as first parameter if the function asks for it:

(If the function has a parameter named $__this, pass $this as parameter)

function the_function($__this, $foo, $bar) {
}

$arguments = array('argument1');

$function = new ReflectionFunction('the_function');
$params = $function->getParameters();
if (count($params) > 0 && $params[0]->name == '__this') {
    array_unshift($arguments, $this);
}

$function->invokeArgs($arguments);

You could do the same with doc comments:

/**
 * @IWantThis
 */
function the_function($__this) {
}

$function = new ReflectionFunction('the_function');
if (preg_match('/@IWantThis/', $function->getDocComment()) { 
    ...


Directly you have two options: Either passing the object to the function or the value to the object. I have no clue if that is the only job the function does, so this might not solve your problem, just showing the alternative as you wrote that passing the object to the function is not an option:

function test($arg1)
{
    return 10;
}

class MyClass
{
    public $code;
    public function call()
    {
         $this->code  = call_user_func("test", "argument1");
    }
}

If you don't want any of those, you must create some context both, the object and the function, operate in, to connect both with each other.

You can create context statically or dynamically. The first is often related to global variables which can result in hard to maintain code over time, an example:

function test($arg1)
{
     global $object;
     $object->code = 10;
}

class MyClass
{
    public $code;
    public function call()
    {
         global $object;
         $object = $this;
         call_user_func("test", "argument1");
         unset($object);
    }
}

To create a more dynamical context, you are encapsulating everything into some context:

class contextCallback
{
    private $object;
    public function __construct($object)
    {
        $this->object = $object;
    }
    public function test()
    {
        $this->object = 10;
    }
}

class MyClass
{
    public $code;
    public function call()
    {
         $callback = new contextCallback($this);
         call_user_func(array($callback, 'test'), "argument1");
         # or:
         $callback->test("argument1");
    }
}

However I think then passing $this as an argument is much simpler and pretty much the same with far less code. I have no clue why you need call_user_func so it stays this abstract.

Edit: As another alternative and to decouple from concrete classes, when you only need to set values, consider returning multiple values:

function test($arg1)
{         
     $object->code = 10;
     return array($value, $object);
}

class MyClass
{
    public $code;
    public function call()
    {
         list($value, $object) = call_user_func("test", "argument1");
         foreach($object as $var => $value)
             $this->$var = $value;
    }
}


You have two choices. Make the method a method of the MyClass object or make the object a parameter of the function.

If you have a function, you want it to do the same thing, every time. This means that if the function depends on some state (like the value of $this), then you need to find a way to either 1. make it global (not an option here) or 2. pass it in as a parameter.

You don't need a $this in that function anyway, you need some object which happens to have an attribute named by whatever the contents of $code is (I think that is a typo actually. I think you mean $this->code not $this->$code).


You could use a closure (php 5.3+) to "pass" the object reference to those functions that need it.
But you'd have to make a difference between "old" functions and "new" extension functions. And the new functions still only have access to public properties/methods of the object.

<?php
class MyClass
{
    public $code = 0;
    protected $functions=array();

    public function call($fn)
    {
        if ( is_string($fn) && isset($this->functions[$fn]) ) {
            $fn =   $this->functions[$fn];
        }

        if ( !is_callable($fn) ) {
            die('add error handler here');
        }
        $rv = call_user_func($fn, 'argument1');
    }

    public function loadFunctions($file) {
        $fnInit = require $file;
        $fns = $fnInit($this);
        $this->functions = array_merge($this->functions, $fns);
    }
}

$m = new MyClass;
$m->loadFunctions('ext.php');
$m->call('oldFn');
$m->call('foo');
$m->call('bar');
echo 'and now $m->code is: ', $m->code;

and as ext.php:

<?php
function oldFn($arg) { // that's probably all you have to do atm to have a new "extension function" for your class
    echo "oldFn($arg)\n";
}


return function($obj) { // and that's more or less how the new functions would have to be declared/defined
    return array(
        'foo'=>function($arg1) use($obj) {
            echo "foo($arg1) + code: $obj->code\n";
            $obj->code = 1;
        },
        'bar'=>function($arg1) use($obj) {
            echo "bar($arg1) + code: $obj->code\n";
            $obj->code = 2;
        }
    );
};

prints

oldFn(argument1)
foo(argument1) + code: 0
bar(argument1) + code: 1
and now $m->code is: 2

( if that seems somehow feasible to you I can write a bit more text ...but not right now ;-) )


call_user_func("test", array($this,"argument1"));

I'm not 100% but you should be able to access it with

function test($arg1)
{
    $arg1[0]->code = 10;
}


Would runkit suit your needs, specifically runkit_function_redefine?

0

精彩评论

暂无评论...
验证码 换一张
取 消