如何"动态"向对象添加新方法?
$me= new stdClass;
$me->doSomething=function ()
{
echo 'I\'ve done something';
};
$me->doSomething();
//Fatal error: Call to undefined method stdClass::doSomething()
Run Code Online (Sandbox Code Playgroud)
kar*_*m79 93
你可以利用__call这个:
class Foo
{
public function __call($method, $args)
{
if (isset($this->$method)) {
$func = $this->$method;
return call_user_func_array($func, $args);
}
}
}
$foo = new Foo();
$foo->bar = function () { echo "Hello, this function is added at runtime"; };
$foo->bar();
Run Code Online (Sandbox Code Playgroud)
Moh*_*ami 43
使用PHP 7,您可以使用匿名类
$myObject = new class {
public function myFunction(){}
};
$myObject->myFunction();
Run Code Online (Sandbox Code Playgroud)
ale*_*oat 18
简单地使用__call以允许在运行时添加新方法的主要缺点是这些方法不能使用$ this实例引用.一切都很好,直到添加的方法不在代码中使用$ this.
class AnObj extends stdClass
{
public function __call($closure, $args)
{
return call_user_func_array($this->{$closure}, $args);
}
}
$a=new AnObj();
$a->color = "red";
$a->sayhello = function(){ echo "hello!";};
$a->printmycolor = function(){ echo $this->color;};
$a->sayhello();//output: "hello!"
$a->printmycolor();//ERROR: Undefined variable $this
Run Code Online (Sandbox Code Playgroud)
为了解决这个问题,你可以用这种方式重写模式
class AnObj extends stdClass
{
public function __call($closure, $args)
{
return call_user_func_array($this->{$closure}->bindTo($this),$args);
}
public function __toString()
{
return call_user_func($this->{"__toString"}->bindTo($this));
}
}
Run Code Online (Sandbox Code Playgroud)
通过这种方式,您可以添加可以使用实例引用的新方法
$a=new AnObj();
$a->color="red";
$a->sayhello = function(){ echo "hello!";};
$a->printmycolor = function(){ echo $this->color;};
$a->sayhello();//output: "hello!"
$a->printmycolor();//output: "red"
Run Code Online (Sandbox Code Playgroud)
Pek*_*ica 12
更新:此处显示的方法有一个主要缺点:新功能不是该类的完全合格成员;
$this当以这种方式调用时,该方法中不存在.这意味着如果要使用对象实例中的数据或函数,则必须将对象作为参数传递给函数!此外,您将无法从这些功能访问private或protected成员.
使用新的匿名函数的好问题和聪明的想法!
有趣的是,这有效:替换
$me->doSomething(); // Doesn't work
Run Code Online (Sandbox Code Playgroud)
通过函数本身的call_user_func :
call_user_func($me->doSomething); // Works!
Run Code Online (Sandbox Code Playgroud)
什么是行不通的是"正确的"方式:
call_user_func(array($me, "doSomething")); // Doesn't work
Run Code Online (Sandbox Code Playgroud)
如果这样调用,PHP需要在类定义中声明该方法.
这是一个 private/ public/ protected可见性问题吗?
更新:不.即使从类中也不可能以正常方式调用函数,因此这不是可见性问题.传递实际功能call_user_func()是我能够做到这一点的唯一方法.