回调作为静态成员数组的一部分

Aus*_*yde 5 php static callback

最近在我正在开发的项目中,我需要将回调存储在静态成员数组中,如下所示:

class Example {
    private static $_callbacks = array(
        'foo'=>array('Example','do_foo'),
        'bar'=>array('Example','do_bar')
    );
    private static function do_foo() { }
    private static function do_bar() { }
}
Run Code Online (Sandbox Code Playgroud)

为了调用它们,我尝试了明显的(甚至是天真的)语法(在Example类中):

public static function do_callbacks() {
    self::$_callbacks['foo']();
    self::$_callbacks['bar']();
}
Run Code Online (Sandbox Code Playgroud)

令我惊讶的是,这不起作用,导致我正在访问一个未定义的变量的通知,以及一个致命错误,指出self::$_callbacks['foo']需要可调用.

然后,我试过call_user_func:

public static function do_callbacks() {
    call_user_func(self::$_callbacks['foo']);
    call_user_func(self::$_callbacks['bar']);
}
Run Code Online (Sandbox Code Playgroud)

它奏效了!

我的问题是:

为什么我需要call_user_func用作中间人,而不是直接打电话给他们?

Art*_*cto 4

您不能通过附加 来调用回调()。这只适用于 PHP 5.3,带有 lambda 函数和实现__invoke魔法的对象(另请参阅内部get_closure对象处理程序)。

\n\n

首先,不管你怎么说,这都行不通:

\n\n
<?php\nclass Example {\n    private static $_callbacks;\n    private static function do_foo() { echo "foo"; }\n    private static function do_bar() { echo "bar"; }\n\n    public static function do_callbacks() {\n        self::$_callbacks[\'foo\'] = array(\'Example\',\'do_foo\');\n        self::$_callbacks[\'bar\'] = array(\'Example\',\'do_bar\');\n\n        self::$_callbacks[\'foo\']();\n        self::$_callbacks[\'bar\']();\n    }\n}\nExample::do_callbacks();\n
Run Code Online (Sandbox Code Playgroud)\n\n

self::$_callbacks[\'foo\']但如果是 lambda,它甚至无法工作:

\n\n
<?php\nclass Example {\n    private static $_callbacks;\n\n    public static function do_callbacks() {\n        self::$_callbacks[\'foo\'] = function () { echo "foo"; };\n\n        self::$_callbacks[\'foo\']();\n    }\n}\n\nExample::do_callbacks();\n
Run Code Online (Sandbox Code Playgroud)\n\n

原因在于解析器。以上编译为:

\n\n
\n类示例:\n函数 do_callbacks:\n(...)\n操作数: 16\n编译变量: !0 = $_callbacks\nline # * op fetch ext return operands\n--------- -------------------------------------------------- ----------------------\n 6 0 > EXT_NOP \n 7 1 EXT_STMT \n 2 ZEND_FETCH_CLASS \n 3 ZEND_DECLARE_LAMBDA_FUNCTION \'%00%7Bclosure%7D% 2Ftmp%2Fcp9aicow0xb7fcd09b\'\n 4 FETCH_W 静态成员 $2 \'_callbacks\'\n 5 ZEND_ASSIGN_DIM $2, \'foo\'\n 6 ZEND_OP_DATA ~3, $4\n 9 7 EXT_STMT \n 8 FETCH_DIM_R $5 !0, \ 'foo\'\n 9 ZEND_FETCH_CLASS \n 10 ZEND_INIT_STATIC_METHOD_CALL $6, $5\n 11 EXT_FCALL_BEGIN \n 12 DO_FCALL_BY_NAME 0 \n 13 EXT_FCALL_END \n 10 14 EXT_STMT \n 15 > RETURN null\n
\n\n

永远不会获取静态成员(除了 lambda 的赋值)。事实上,PHP 编译了一个变量$_callbacks,结果在运行时并不存在;因此你的错误。我承认这可能不是一个错误,但至少是解析器的一个极端情况。它首先评估该$_callbacks[\'foo\']部分,然后尝试调用其名称由该评估产生的静态函数。

\n\n

总之 \xe2\x80\x93 坚持call_user_funcor forward_static_call

\n