将代码(方法)注入类中?

时间:2011-04-19 21:40:21

标签: php oop

采用这个简单的代码:

class MyClass {
   public $customFunction = array();

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

//> Usage:

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

$c->run('first');

这个cose的作用就像被驱逐一样。我将该函数添加到$customFunction,然后我可以将其称为run();方法。

问题出现在我注入的函数中,我尝试做一些与对象相关的事情,例如,如果我添加这个函数:

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

当我调用run();方法时,PHP说我不能在静态上下文中使用$this

我是否有办法注入这些功能并能够使用对象方法?

(注意:当然我的课只是一个例子,我需要这个范围)
感谢

感谢Mario,我将使用以下解决方案:

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

此时我只需要添加像这样的parm函数:

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

$this将模拟对象上下文范围。

4 个答案:

答案 0 :(得分:5)

错误源自您在示例中显示为/* some code*/的代码。

您可以在此处指定匿名函数:

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

它仍然只是一个功能。它不会成为班级的真正方法。因此,在其中使用$this将无效。


解决方法:将自定义函数传递给$obj参数,让他们使用该参数代替$this。 (真的,只是一个古怪的解决方法;但可行。)

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

或者尝试使用classkit_method_addrunkit来获得“正确”的解决方案。 - 如果在PHP中可用。

答案 1 :(得分:1)

抱歉,你无法做到这一点。

然而,像往常一样,我确实有一些诡计。 :)

你可以这样做:

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);
    }

}

使用示例:

class MyClass extends Test { }

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

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

答案 2 :(得分:1)

使用对象而不是匿名函数,并遵循以下基本代码:

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();
    }
}

最终用法:

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');

以上代码依赖于command patterndependency injection

答案 3 :(得分:0)

不幸的是,you can't do that

你能做的最好的事情(至少没有造成脑损伤)是使用__call魔法并将$ this传递到你的lambda范围内,因为$ 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');

输出:

  

嗨,莎莉!