3

总体思路是这样的:

  • 我有一堂课test
  • 该类具有公共静态属性$commands
  • test::$commands是对key => Callback数组
  • 我有一把钥匙保存在$cmdkey

考虑到所有这些,我应该可以这样写:

self::$commands[$cmdkey]($argument);

但是,这样做会产生:

PHP 注意:未定义变量:$commands
PHP 致命错误:函数名必须是字符串

我通过这样做解决了这个问题:

$callback = self::$commands[$cmdkey];
$callback($argument);

不过,在取消引用是 PHP 中的一件事之前,这是一种反击……

我疯了,还是我真的在 PHP 解析器中发现了一个错误?

4

1 回答 1

3

看起来像

test::$commands[$cmdkey](foo)

被解释为

test::($commands[$cmdkey])(foo)

即首先获取$commands[$cmdkey]包含的内容并将其用作test. 请注意,只是test::$commands[$cmdkey]正常绑定。

考虑:

class test {
    public static $commands = array('x' => 'strlen');

    public static function other() {
        print 'here!';
    }
}

$cmdkey = 'x';

$commands = array('x' => 'other'); // *

print test::$commands[$cmdkey]('abc');

如果您注释掉该*行,您将得到

Notice: Undefined variable: commands...
Fatal error: Function name must be a string...

可悲的是,http: //www.php.net/manual/en/language.operators.precedence.php 缺乏::所以很难说这种行为是否是有意的,但这绝对是违反直觉的。

这就是PHPParser所说的:

$code = <<<'EOF'
<?php test::$commands[123](456); ?>
EOF;

$parser = new PhpParser\Parser(new PhpParser\Lexer);
$stmts = $parser->parse($code);
$nodeDumper = new PhpParser\NodeDumper;
print $nodeDumper->dump($stmts);

结果:

0: Expr_StaticCall(
    class: Name(
        parts: array(
            0: test
        )
    )
    name: Expr_ArrayDimFetch(
        var: Expr_Variable(
            name: commands
        )
        dim: Scalar_LNumber(
            value: 123
        )
    )
    args: array(
        0: Arg(
            value: Scalar_LNumber(
                value: 456
            )
            byRef: false
            unpack: false
        )
    )
)
于 2014-06-27T10:40:30.757 回答