我在类外部有一个函数,我使用call_user_func
从内部调用它,我的问题是我无法访问函数内部的类。如果有一种方法可以使$this
在函数中工作,那么我需要一种在不传递参数的情况下访问类的方法。
除了将带有参数的类传递到函数之外的任何建议都将受到赞赏;
function test($arg1)
{
$this->code = 10; // i know $this won't work here,
// but i need a way to change $code
// property from this function without
// passing class into this function by using arguments
}
class MyClass
{
public $code;
public function call()
{
call_user_func("test", "argument1");
}
}
如果你能在类中移动函数,你就可以这样调用它:
call_user_func(array($this, 'the_function'));
如果你有PHP5.3,你可以使用一个闭包:
$that = $this;
$function = function() use ($that) {
// use $that instead of $this
};
call_user_func($function);
如果你可以添加一个参数,你可以这样做:
call_user_func('the_function', "argument1", $this);
如果函数要求传递$this
作为第一个参数:
(如果函数有一个名为$__this
的参数,则将$this
作为参数传递(
function the_function($__this, $foo, $bar) {
}
$arguments = array('argument1');
$function = new ReflectionFunction('the_function');
$params = $function->getParameters();
if (count($params) > 0 && $params[0]->name == '__this') {
array_unshift($arguments, $this);
}
$function->invokeArgs($arguments);
你可以对文档注释做同样的操作:
/**
* @IWantThis
*/
function the_function($__this) {
}
$function = new ReflectionFunction('the_function');
if (preg_match('/@IWantThis/', $function->getDocComment()) {
...
直接有两个选项:将对象传递给函数或将值传递给对象。我不知道是否是函数所做的唯一工作,所以这可能无法解决你的问题,只是在你写的将对象传递给函数不是一个选项时显示了另一种选择:
function test($arg1)
{
return 10;
}
class MyClass
{
public $code;
public function call()
{
$this->code = call_user_func("test", "argument1");
}
}
如果你不想要其中的任何一个,你必须创建一些上下文,对象和函数,在中操作,以将两者相互连接。
您可以静态或动态地创建上下文。第一种通常与全局变量有关,随着时间的推移,全局变量可能导致代码难以维护,例如:
function test($arg1)
{
global $object;
$object->code = 10;
}
class MyClass
{
public $code;
public function call()
{
global $object;
$object = $this;
call_user_func("test", "argument1");
unset($object);
}
}
要创建一个更动态的上下文,您需要将所有内容封装到某个上下文中:
class contextCallback
{
private $object;
public function __construct($object)
{
$this->object = $object;
}
public function test()
{
$this->object = 10;
}
}
class MyClass
{
public $code;
public function call()
{
$callback = new contextCallback($this);
call_user_func(array($callback, 'test'), "argument1");
# or:
$callback->test("argument1");
}
}
然而,我认为将$this
作为参数传递要简单得多,而且代码要少得多。我不知道你为什么需要call_user_func
,所以它一直是抽象的。
编辑:作为另一种选择,为了与具体类解耦,当您只需要设置值时,请考虑返回多个值:
function test($arg1)
{
$object->code = 10;
return array($value, $object);
}
class MyClass
{
public $code;
public function call()
{
list($value, $object) = call_user_func("test", "argument1");
foreach($object as $var => $value)
$this->$var = $value;
}
}
您有两个选择。使该方法成为MyClass
对象的方法,或者使该对象成为函数的参数。
如果你有一个函数,你希望它做同样的事情,每一次。这意味着,如果函数依赖于某种状态(如$this
的值(,那么您需要找到一种方法来获得1。将其设为全局(此处不是选项(或2。将其作为参数传入。
无论如何,在该函数中您不需要$this
,您需要一些对象,该对象恰好具有以$code
的内容命名的属性(我认为这实际上是一个拼写错误。我认为您指的是$this->code
而不是$this->$code
(。
您可以使用闭包(php 5.3+(将对象引用"传递"给那些需要它的函数。
但是,您必须区分"旧"函数和"新"扩展函数。新函数仍然只能访问对象的公共属性/方法。
<?php
class MyClass
{
public $code = 0;
protected $functions=array();
public function call($fn)
{
if ( is_string($fn) && isset($this->functions[$fn]) ) {
$fn = $this->functions[$fn];
}
if ( !is_callable($fn) ) {
die('add error handler here');
}
$rv = call_user_func($fn, 'argument1');
}
public function loadFunctions($file) {
$fnInit = require $file;
$fns = $fnInit($this);
$this->functions = array_merge($this->functions, $fns);
}
}
$m = new MyClass;
$m->loadFunctions('ext.php');
$m->call('oldFn');
$m->call('foo');
$m->call('bar');
echo 'and now $m->code is: ', $m->code;
和ext.php:
<?php
function oldFn($arg) { // that's probably all you have to do atm to have a new "extension function" for your class
echo "oldFn($arg)'n";
}
return function($obj) { // and that's more or less how the new functions would have to be declared/defined
return array(
'foo'=>function($arg1) use($obj) {
echo "foo($arg1) + code: $obj->code'n";
$obj->code = 1;
},
'bar'=>function($arg1) use($obj) {
echo "bar($arg1) + code: $obj->code'n";
$obj->code = 2;
}
);
};
打印
oldFn(argument1)
foo(argument1) + code: 0
bar(argument1) + code: 1
and now $m->code is: 2
(如果这在某种程度上对你来说可行的话,我可以写更多的文本……但现在不行;-(
call_user_func("test", array($this,"argument1"));
我不是100%,但你应该可以用访问它
function test($arg1)
{
$arg1[0]->code = 10;
}
runkit
是否适合您的需求,特别是runkit_function_redefine
?