假设这个类代码:
class Foo {
function method() {
echo 'works';
}
}
有没有办法存储对method
个实例的Foo
方法的引用?
我只是在试验和摆弄,我的目标是检查PHP是否允许每次调用$FooInstance->method()
而不写$FooInstance->
。我知道我可以为此编写函数包装器,但我更感兴趣的是获取对实例方法的引用。
例如,这个伪代码理论上会将$foo->method
存储在$method
变量中:
$foo = new Foo();
$method = $foo->method; //Undefined property: Foo::$method
$method();
显然,由于method
是一种方法而我没有用()
调用它,解释器认为我正在寻找一个属性,因此这不起作用。
我已阅读Returning References,但这些示例仅显示如何返回对变量的引用,而不是方法。
因此,我调整了我的代码以在变量中存储匿名函数并返回它:
class Foo {
function &method() {
$fn = function() {
echo 'works';
};
return $fn;
}
}
$foo = new Foo();
$method = &$foo->method();
$method();
这很有效,但相当丑陋。此外,没有简单的方法可以一次调用它,因为这似乎需要在调用它之前将返回的函数存储在变量中:$foo->method()();
和($foo->method())();
是语法错误。
另外,我尝试直接返回匿名函数而不将其存储在变量中,但后来我收到以下通知:
注意:只能通过引用
返回变量引用
这是否意味着返回/存储对类实例方法的引用是不可能/不鼓励的,还是我忽略了什么?
更新:我不介意在必要时添加一个getter,目标只是获取对该方法的引用。我甚至尝试过:
class Foo {
var $fn = function() {
echo 'works';
};
function &method() {
return $this->fn;
}
}
但是从unexpected 'function' (T_FUNCTION)
错误我认为PHP明智地不允许属性存储函数。
我开始相信,如果不使用丑陋的黑客作为eval()
,我的目标就不容易实现。
答案 0 :(得分:5)
是的。您必须使用具有两个值的数组:类实例(如果您调用静态方法,则为类名的字符串),方法名称为字符串。这在Callbacks Man page:
中有记录实例化对象的方法作为数组传递,该数组包含索引为0的对象和索引为1的方法名称。
演示(Codepad):
<?php
class Something {
public function abc() {
echo 'called';
}
}
$some = new Something;
$meth = array($some, 'abc');
$meth(); // 'called'
请注意,这也适用于需要回调的内置函数(Codepad):
class Filter {
public function doFilter($value) {
return $value !== 3;
}
}
$filter = new Filter;
$test = array(1,2,3,4,5);
var_dump(array_filter($test, array($filter, 'doFilter'))); // 'array(1,2,4,5)'
对于静态方法 - 请注意'Filter'
而不是类的实例作为数组中的第一个元素(Codepad):
class Filter {
public static function doFilter($value) {
return $value !== 3;
}
}
$test = array(1,2,3,4,5);
var_dump(array_filter($test, array('Filter', 'doFilter'))); // 'array(1,2,4,5)'
// -------- or -----------
var_dump(array_filter($test, 'Filter::doFilter')); // As of PHP 5.2.3
答案 1 :(得分:4)
是的,你可以。 PHP有一个“可调用的”伪类型,实际上它只是一个字符串或一个数组。我想到了几个函数(usort
)接受“回调”类型的参数:实际上,它们只需要函数名称或对象 - 方法对。
没错,字符串可以调用:
$fn = "strlen";
$fn("string"); // returns 6
如上所述,也可以使用数组作为回调。在这种情况下,第一个元素必须是一个对象,第二个参数必须是方法名称:
$obj = new Foo();
$fn = array($obj, "method");
$fn(); // calls $obj->method()
以前,您必须使用call_user_func
来调用它们,但是最近版本中的语法糖可以直接对变量执行调用。
您可以在"callable" documentation page上阅读更多内容。
答案 2 :(得分:0)
不,据我所知,它无法在PHP中存储对方法的引用。在数组中存储对象/类名和方法名有效,但它只是一个没有任何特殊含义的数组。您可以根据需要使用阵列,例如:
$ref = [new My_Class(), "x"];
// all is fine here ...
$ref();
// but this also valid, now the 'reference' points to My_Other_Class::x()
// do you expect real reference to behave like this?
$ref[0] = new My_Other_Class();
$ref();
// this is also valid syntax, but it throws fatal error
$ref[0] = 1;
$ref();
// let's assume My_Class::y() is a protected method, this won't work outside My_Class
$ref = [new My_Class(), 'y'];
$ref();
我个人更喜欢使用lambdas:
$ref = function() use($my_object) { $my_object->x(); }
如果你从$my_object
内部执行此操作,由于访问$this
,它变得不那么笨重了:
$ref = function() { $this->x(); }