我想知道是否有一种方法可以在运行时在php中将新方法附加到类中。 我的意思是,不是在实例级别,而是直接到类,以便所有新创建的实例都有这个新方法。 这样的事情能用反射来完成吗?php在运行时创建类方法
感谢
我想知道是否有一种方法可以在运行时在php中将新方法附加到类中。 我的意思是,不是在实例级别,而是直接到类,以便所有新创建的实例都有这个新方法。 这样的事情能用反射来完成吗?php在运行时创建类方法
感谢
是的,你可以。
下面是在运行时在php 5.4.x中创建方法的方法。
匿名函数由从5.3.x开始的Closure类表示。从5.4.x开始,它添加一个Closure::bind静态方法来将匿名函数绑定到特定的对象或类。
实施例:
class Foo {
private $methods = array();
public function addBar() {
$barFunc = function() {
var_dump($this->methods);
};
$this->methods['bar'] = \Closure::bind($barFunc, $this, get_class());
}
function __call($method, $args) {
if(is_callable($this->methods[$method]))
{
return call_user_func_array($this->methods[$method], $args);
}
}
}
$foo = new Foo;
$foo->addBar();
$foo->bar();
你已经采取了看看在文档create_function()?你也可以通过overloading达到预期的结果。
有没有玩过整个事情。似乎只有你可以用ReflectionClass
做的事情是替换现有的方法。但即使如此也是间接的。
我实际上不知道任何基于类的语言,其中存在动态类(然后再次,我的知识是相当有限的)。我只看到它在基于原型的语言(javascript,ruby,smalltalk)中完成。相反,你可以做什么,在PHP 5.4,是使用Closure
并添加新的方法,现有对象。
这是一类将让你执行这样变态到任何对象:
class Container
{
protected $target;
protected $className;
protected $methods = [];
public function __construct($target)
{
$this->target = $target;
}
public function attach($name, $method)
{
if (!$this->className)
{
$this->className = get_class($this->target);
}
$binded = Closure::bind($method, $this->target, $this->className);
$this->methods[$name] = $binded;
}
public function __call($name, $arguments)
{
if (array_key_exists($name, $this->methods))
{
return call_user_func_array($this->methods[$name] , $arguments);
}
if (method_exists($this->target, $name))
{
return call_user_func_array(
array($this->target, $name),
$arguments
);
}
}
}
要利用这一点,你必须提供的构造与现有对象。这里是一个小例子的用法:
class Foo
{
private $bar = 'payload';
};
$foobar = new Foo;
// you initial object
$instance = new Container($foobar);
$func = function ($param)
{
return 'Get ' . $this->bar . ' and ' . $param;
};
$instance->attach('test', $func);
// setting up the whole thing
echo $instance->test('lorem ipsum');
// 'Get payload and lorem ipsum'
不完全是你想要的,但AFAIK这是尽可能接近你可以得到。
,这是可能与runkit扩展的runkit_method_add()。虽然在生产中要小心使用它。
例子:
<?php
class Example {}
$e = new Example();
runkit_method_add(
'Example',
'add',
'$num1, $num2',
'return $num1 + $num2;',
RUNKIT_ACC_PUBLIC
);
echo $e->add(12, 4);
太棒了。喜欢这个新的PHP特性 – Thomas
这里的__call方法有什么意义,如果\ Closure :: bind做的事情,反之亦然? – jayarjo
@jayarjo''\ Closure :: bind'改变了匿名函数的上下文(在这种情况下,它确保在关闭中'$ this'指向正确的对象)。但是,它不会将该函数转换为'$ this'的方法。我们仍然需要'__call'来允许外部代码像调用方法那样调用闭包。 –