我想知道是否有一种方法可以在运行时将新方法附加到类中,在 php.ini 中。我的意思是,不是在实例级别,而是直接在类中,以便所有新创建的实例都有这个新方法。这样的事情可以用反射来完成吗?
谢谢
我想知道是否有一种方法可以在运行时将新方法附加到类中,在 php.ini 中。我的意思是,不是在实例级别,而是直接在类中,以便所有新创建的实例都有这个新方法。这样的事情可以用反射来完成吗?
谢谢
是的你可以。
下面是 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();
做了一些玩弄整个事情。似乎您唯一可以做的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 这是你能得到的最接近的。
您是否查看过文档中的create_function()?您也可以通过重载.
这可以通过 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);
您也可以使用以下两种方法之一。
function method1()
{
echo "In method one.";
}
function method2()
{
echo "In method two.";
}
class DynamicClass
{
function __construct(){
$function_names = ['method1'];
foreach ($function_names as $function_name) {
if (function_exists($function_name)) {
$this->addMethod($function_name);
}
}
}
function addMethod($name)
{
$this->{$name} = Closure::fromCallable($name);
}
public function __call($name, $arguments)
{
return call_user_func($this->{$name}, $arguments);
}
}
$obj = new DynamicClass();
//Call method1 added in constructor
$obj->method1();
//Add method
$obj->addMethod('method2');
$obj->method2();