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)
ThanksThanks 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!
精彩评论