/**
* Example in PHP 5.3
*/
class Meta
{
private $methods = array();
public function addMethod($methodName, $methodCallable)
{
if (!is_callable($methodCallable)) {
throw new InvalidArgumentException('Second param must be callable');
}
$this->methods[$methodName] = $methodCallable;
}
public function __call($methodName, array $args)
{
if (isset($this->methods[$methodName])) {
array_unshift($args, $this);
return call_user_func_array($this->methods[$methodName], $args);
}
throw RunTimeException('There is no method with the given name to call');
}
}
/**
* Example in PHP 5.3
*/
require 'Meta.php';
$meta = new Meta();
$meta->addMethod('color', function ($self) {
$self->name = 'My Name';
return '#00000';
});
echo $meta->color(), PHP_EOL;
echo $meta->name, PHP_EOL;
GitHub 的链接 https://gist.github.com/krolow/4189729#file-meta-php
它是如何工作的?
它使匿名函数和魔术方法__call,该类元有方法addMethod的使用,这种方法是等待两个参数,第一个是方法名,第二个可调用匿名函数。
每次调用原始对象没有(未在类中声明)的方法,该方法调用一下,函数调用将寻找你是否有给定名称注册一个新的方法,如果是,它调用匿名函数,传参数给当前对象的匿名函数,所以你可以访问类的方法和属性。
它有一定的局限性,你将不能访问私有的方法和属性,但它有可能使用象反射这样的方法来处理。
在PHP5.4中添加方法的对象
trait MetaTrait
{
private $methods = array();
public function addMethod($methodName, $methodCallable)
{
if (!is_callable($methodCallable)) {
throw new InvalidArgumentException('Second param must be callable');
}
$this->methods[$methodName] = Closure::bind($methodCallable, $this, get_class());
}
public function __call($methodName, array $args)
{
if (isset($this->methods[$methodName])) {
return call_user_func_array($this->methods[$methodName], $args);
}
throw new RunTimeException('There is no method with the given name to call');
}
}
require 'MetaTrait.php';
class HackThursday {
use MetaTrait;
private $dayOfWeek = 'Thursday';
}
$test = new HackThursday();
$test->addMethod('when', function () {
return $this->dayOfWeek;
});
echo $test->when();