【问题标题】:error when using variable class name and static method使用变量类名和静态方法时出错
【发布时间】:2015-05-22 23:28:58
【问题描述】:

运行 PHP 5.4,所以我没想到会这样,但我遇到了以下错误:

Parse error: syntax error, unexpected '::' (T_PAAMAYIM_NEKUDOTAYIM)

假设你有一个stdClass的变量设置如下:

$this->variable = new stdClass();

$this->variable->other = array('class' => 'helloworld');

现在,假设您要访问 helloworld 类的静态方法:

// Standard call
$x = helloworld::my_static_method();

// Call with variable class name
$x = $this->variable->other['class']::my_static_method();

当使用变量类名调用上述内容时,我收到解析错误。奇怪的是,如果我执行以下操作,则不会出现错误:

$class = $this->variable->other['class'];

$x = $class::my_static_method();

在我看来,这似乎很奇怪,谁能想到在使用第一个示例与第二个示例时类名无法正确解析的原因?

【问题讨论】:

    标签: php


    【解决方案1】:

    这不起作用($this->variable->other['class']::my_static_method()),因为它本质上是直接使用字符串作为类名。当你首先将它分配给一个变量时它会起作用,因为它会被评估为类名。

    您还可以考虑使用ReflectionMethod 调用来调用该方法,在这种情况下,您不必在使用之前将类名存储在变量中。以下是相关文档:http://php.net/manual/en/class.reflectionmethod.phpinvoke 方法(传入 NULL 表示静态方法)http://php.net/manual/en/reflectionmethod.invoke.php

    以下是调用函数的几个示例:

    class helloworld{
        public static function my_static_method($i = 0){
            echo "Here: ".$i;
        }
    }
    
    class Foo{
        private $variable;
    
        public function __construct(){
            //Create a new class
            $this->variable = new stdClass();
    
            //Create a new property of the class, storing an array
            $this->variable->other = array('class' => 'helloworld');
    
            //Call function statically
            $x = helloworld::my_static_method(1); //Outputs: "Here: 1"
    
            //Store class name in a variable before use
            $class = $this->variable->other['class'];
            $y = $class::my_static_method(2); //Outputs: "Here: 2"
    
            //Using a ReflectionMethod, you can call the function this way, too
            $z = new ReflectionMethod($this->variable->other['class'], 'my_static_method');
            $z->invoke(null, 3); //Outputs: "Here: 3"
        }
    }
    
    //Instantiate new Foo class
    new Foo();
    

    【讨论】:

    • 有趣 - 我想我只是好奇为什么(在你的例子中)$class 正确解析,但 $this->variable->other['class'] 没有?在我看来,这两个变量都解析为字符串helloworld。在您的评论中,“......它本质上是直接使用一个字符串作为类名。当您首先将它分配给一个变量时,它会起作用,因为它会被评估为类名。”为什么不将它们都评估为类名?
    • 这也很有趣,因为调用new $this->variable->other['class']() 有效……那不属于同一个问题吗?
    • 所以,有趣的是,当您使用$this->variable->other['class'] 时,它被评估为一个字符串。字符串没有:: 方法(即解析器无法识别字符串的静态方法调用),这就是您需要使用变量的原因(在这种情况下,解析器能够将变量内容评估为类,并且静态方法调用有效)。在您的第二条评论中,由于您不再使用静态方法调用,$this->variable->other['class']() 按预期工作。
    • 您可以在此处查看有关某些动态语言功能的一些信息(尽管它是基于命名空间的文档):php.net/manual/en/language.namespaces.dynamic.php 以及此处的类参考文档:php.net/manual/en/language.oop5.basic.php
    【解决方案2】:

    谁能想到在使用第一个示例与第二个示例时类名无法正确解析的原因?

    PHP 解析器不支持这样的语法,仅此而已。这是因为解析器在历史上已经成长。我不能给出更多的理由。

    在 PHP 7 中,您可以看到这些语法细节上的一些变化更符合您的预期方向Uniform Variable Syntax

    ($variable->other['class'])::my_static_method();
    

    但在那之前,您可以在 call_user_func 的帮助下解决这个问题:

    call_user_func([$variable->other['class'], 'my_static_method']);
    call_user_func($variable->other['class'] . '::my_static_method');
    

    或者你自己写的,通过创建一个变量:

    $class = $variable->other['class'];
    $class::my_static_method();
    

    甚至是看起来不同的变量:

    ${(int)!${0}=$variable->other['class']}::my_static_method();
    

    相关资料:

    【讨论】:

    • 感谢您的解释。很高兴看到他们将支持 PHP 7 的一些更奇特的语法使用。
    • 我不会说 PHP 7 的语法是异乎寻常的,即使反过来:它更一致。我很高兴终于解决了这个问题:)
    猜你喜欢
    • 2011-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-30
    • 1970-01-01
    • 1970-01-01
    • 2014-01-31
    • 2017-04-16
    相关资源
    最近更新 更多