开发者

injecting codes (methods) into class?

Take this simple code:

class MyClass {
   public $cust开发者_开发问答omFunction = array();

   public function run($name){
       call_user_func($this->customFunction[$name]);
   }
}

//> Usage:

$c = new MyClass();
$c->customFunction['first'] = function (){ /* some code*/ };

$c->run('first');

This cose works as excpted. I add that function to $customFunction and then i can call it form run(); method.

The problem comes when in my injected function I try to do something object-related, for example if i add this function:

$c->customFunction['first'] = function(){ $this->callsomemethod(); }

When i call the run(); method PHP says I can't use $this in a static context.

Do I have some way to inject those function and be able to use the object method?

(Note: of course my class is just an example, I need this for a scope)

Thanks

Thanks to Mario, here the solution I will use:

public function run($name) {
    call_user_func($this->customFunction[$name],$this);
}

At this point i just need to add function with a parm like this:

= function ($this) { /*some code*/};

And $this will emulate the object-context scope.


The error originates in the code you have shown as /* some code*/ in your example.

You assign an anonymous function here:

$c->customFunction['first'] = function (){ /* some code*/ };

And it remains just a function. It doesn't become a real method of the class. So using $this within it won't work.


Workaround: Pass your custom functions an $obj parameter, and have them use that instead of $this. (Really, just a quirky workaround; but doable.)

call_user_func($this->customFunction[$name], $obj=$this);

Or try classkit_method_add or runkit for a "proper" solution. - If available in your PHP.


Use objects rather anonymous functions and follow this basic code:

interface Command {
    public function execute();
}

interface MyClassAware {
    public function setMyClass(MyClass $myClass);
}

class MyClass {
    private $customCommands = array();

    public function addCustomCommand($name, Command $command) {
        $this->customCommands[$name] = $command;
    }

    public function execute($name) {
        $command = $this->customCommands[$name];

        if ($command instanceof MyClassAware) {
            $command->setMyClass($this);
        } 

        $command->execute();
    }
}

Final usage:

class DoSthCommand implements Command, MyClassAware {
    private $myClass;

    public function setMyClass(MyClass $myClass) {
        $this->myClass = $myClass;
    }

    public function execute() {
        // do sth

        $this->myClass->doSthElse();

        // do sth
    }
}

$myCustomCommand = new DoSthCommand();
$myClass->addCustomCommand('doSth', $myCustomCommand);

$myClass->execute('doSth');

The above code relies on command pattern and dependency injection


There's no way you can do that, sorry.

However, as usual, I do have a couple of tricks up my sleeve. :)

You can do this:

class Test {

    static protected $funcs_static=array();
    protected $funcs_dynamic=array();

    public static function register_static($function){
        self::$funcs_static[]=$function;
    }

    public static function register_dynamic($function){
        $this->$funcs_dynamic[]=$function;
    }

    public function __call($name, $arguments) {
        return call_user_func_array($name,$arguments);
    }

    public static function __callStatic($name, $arguments) {
        return call_user_func_array($name,$arguments);
    }

}

Example of use:

class MyClass extends Test { }

MyClass::register_static(function(){
    echo 'bark';
});

$catdog = new MyClass();
$catdog->register_dynamic(function(){
    echo 'beow';
});


Unfortunately, you can't do that.

The best you can do (at least without doing brain damage), is use __call magic and pass $this into your lambda's scope as $something_other_than_$this:

<?php

class Greeter {

  public $greeting = 'Hi';
  public $customFns;
  public function __construct($sayHiMethod){
    $this->customFns['sayHi'] = $sayHiMethod;
  }

  public function __call($name,$args){
    $args['caller']=$this;
    return call_user_func_array($this->customFns[$name],$args);
  }
}

$myGreeter = new Greeter(function($who,$caller){ echo "{$caller->greeting}, {$who}!\n"; });

$myGreeter->sayHi('Sally');

Outputs:

Hi, Sally!

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜