我想知道是否有一種方法可以在運行時在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'來允許外部代碼像調用方法那樣調用閉包。 –