为什么可以从字符串变量实例化一个类,而不是PHP中的字符串?

时间:2015-09-08 21:43:14

标签: php

PHP如何运作:

$myClass = 'MyClass';
$object = new 'App\\'.$myClass;

但这会导致错误:

unexpected T_CONSTANT_ENCAPSED_STRING

在第二个示例中,抛出了new

事实证明,上述示例归因于operator precedence,因为$object = new 'App\MyClass'; 具有最高优先级,但是......

同样,我可以尝试使用一个字符串进行实例化,如:

{{1}}

抛出同样的错误。这是为什么?

4 个答案:

答案 0 :(得分:4)

解析器的实现不是通用的,因此在某些情况下,解析器会打扰引擎实际上可以处理的事情。那里(仍然)甚至不是PHP的官方正式语法,这使得很难预测这样的事情,而不是简单地尝试它们。这是PHP世界的方式:)

答案 1 :(得分:4)

PHP期望对象定义的变量或名称引用,它只是不允许字符串。你可以使用这个基于''空字符串命名变量的hack立即创建和使用,基于${''}评估为$obj = new ${!${''} = 'App\MyClass'}(); 的事实,如下所示从字符串创建一个对象:

Function FindLastRowNotBlank(ByRef ws As Worksheet, ByRef firstRow As Long, _ 
ByRef column As Long) As Long
Dim lastRow As Long
lastRow = firstRow
If ws.Cells(lastRow, column).Value <> "" Then
    Do While ws.Cells(lastRow, column).Value <> ""
        lastRow = lastRow + 1
    Loop
    FindLastRowNotBlank = lastRow - 1 'the last entry is the blank row so needs to subtract 1 from the result
Else
    FindLastRowNotBlank = 0 'Returns 0 if the firstRow is empty
    Exit Function
End If
End Function

答案 2 :(得分:3)

PHP语法在zend_language_parser.y中定义,它没有为new运算符定义任何更复杂的表达式:

new_expr:
    T_NEW class_name_reference ctor_arguments
            { $$ = zend_ast_create(ZEND_AST_NEW, $2,  }
    |   T_NEW anonymous_class
            { $$ = $2; }

class_name_reference的位置:

class_name_reference:
        class_name      { $$ = $1; }
    |   new_variable    { $$ = $1; }

new_variable允许一组有限的变量表达式:

new_variable:
        simple_variable
            { $$ = zend_ast_create(ZEND_AST_VAR, $1); }
    |   new_variable '[' optional_expr ']'
            { $$ = zend_ast_create(ZEND_AST_DIM, $1, $3); }
    |   new_variable '{' expr '}'
            { $$ = zend_ast_create(ZEND_AST_DIM, $1, $3); }
    |   new_variable T_OBJECT_OPERATOR property_name
            { $$ = zend_ast_create(ZEND_AST_PROP, $1, $3); }
    |   class_name T_PAAMAYIM_NEKUDOTAYIM simple_variable
            { $$ = zend_ast_create(ZEND_AST_STATIC_PROP, $1, $3); }
    |   new_variable T_PAAMAYIM_NEKUDOTAYIM simple_variable
            { $$ = zend_ast_create(ZEND_AST_STATIC_PROP, $1, $3); }
// Copyright (c) 1998-2015 Zend Technologies Ltd., the Zend license 2.00

这就是为什么你不能在那里有字符串表达式。 (它从未扩展,因为普通的实例化和$ classvarnames通常就足够了。因此,当引入时,允许的语法与PHP3中的大致相同。)

答案 3 :(得分:1)

这是因为运营商优先: http://php.net/manual/en/language.operators.precedence.php

因为'new'的优先级高于'。'它首先得到处理。

就你的代码而言,编译器看到的是:

$myClass = 'MyClass';
$object = new 'App\\';
$object = $object . $myClass;

对于问题的第二部分,为什么:$object = new 'App\MyClass';不起作用。我不确定。

如果我不得不猜测我会说这是因为当你执行new 'App\MyClass'时,解析器在遇到它时不知道它是一个字符串。直到该行已被处理,它不知道它是否处理字符串,数字,对象等。它可以发现并正确地将其转换为字符串,但我猜这会回到运算符优先级,它不会在处理'new'操作符之前,请执行这些类型的强制转换。

奇怪的是,我刚刚在Quercus PHP中对它进行了测试,它运行良好。正如其他人所提到的,php并不是一种完全定义的语言,所以像这样的事情表现为实现之间的差异。