Php 用额外的步骤从字符串初始化类?

Php 用额外的步骤从字符串初始化类?,php,string,class,initialization,Php,String,Class,Initialization,我一直在研究用PHP中的字符串来证实一个新的类实例。这似乎是一个可以接受的过程,但是我很好奇为什么不能用函数调用的返回来完成。我在下面发布了一个简短的测试,结果表明如果存在变量中介(即$bar=new$foo->callBar();不起作用,而$x=$foo->callBar();$bar=new$x;起作用) 警告:未捕获错误:类名必须是有效的对象或字符串 在php外壳代码中:1堆栈跟踪: #第1行php外壳程序代码中抛出0{main} 我很想知道为什么会这样,或者如果我错了,那么进行此操作的

我一直在研究用PHP中的字符串来证实一个新的类实例。这似乎是一个可以接受的过程,但是我很好奇为什么不能用函数调用的返回来完成。我在下面发布了一个简短的测试,结果表明如果存在变量中介(即
$bar=new$foo->callBar();
不起作用,而
$x=$foo->callBar();$bar=new$x;
起作用)

警告:未捕获错误:类名必须是有效的对象或字符串
在php外壳代码中:1堆栈跟踪:
#第1行php外壳程序代码中抛出0{main}


我很想知道为什么会这样,或者如果我错了,那么进行此操作的正确原因是什么?

我知道使用
new
创建类实例有四种方法:

  • 直接命名类:
    $bar=新条
  • 直接使用变量:
    $barName='Bar'$bar=新的$barName
  • 使用对象属性:
    $obj=(对象)['barName'=>'Bar']$bar=new$obj->barName
  • 使用现有实例:
    $bar1=新条$bar2=新的$bar1
你问题的前半部分答案是PHP解析器:它禁止许多可以用来构建黑客的东西,比如
new(Foo)
new“Foo”


第二部分可能隐藏在PHP源代码中:这会引发异常。

如PHP手册中所述,
new
关键字接受字符串或对象作为类名。您可以选择在末尾的括号中为构造函数提供参数

这意味着语法大致预期:

    new         [string|object]     ()
//  ^^ keyword  ^^ name             ^^ optional parentheses
另一个重要事实是关键字
new
在所有运算符中具有最高的优先级

将这两个事实结合在一起意味着我们不能使用括号来增加带有
new
关键字的操作的优先级。如果我们使用括号,PHP会将其视为
new
语法的可选部分。像这样的事情是行不通的

$bar = new   ($foo->callBar());
//         ^ missing class name
没有明确的方法告诉PHP解析器以其他方式处理这个问题

还有另一个值得记住的警告,爱德华·苏洛夫在他的回答中部分提到了这一点。类名可以来自字符串或实例的任何变量。
以下代码将创建类
Bar
的对象:

$obj = ['a'=>'Bar'];
$bar = new $obj['a'];
// or
$obj = (object) ['a'=>'Bar'];
$bar = new $obj->a;
那么,让我们来解释一下代码的作用

    new         $foo->callBar     ()
//  ^^ keyword  ^^ name           ^^ optional parentheses
因为您的
Foo
类没有属性
callBar
,它将触发通知消息,但PHP将检查它是否可以用作类名。因为它不存在,所以不能是字符串或实例,这就是为什么您会看到错误

这已在PHP8中修复
委员会讨论了这个问题。现在,您可以在创建类的实例时使用表达式。唯一需要注意的是运算符的优先级。调用函数/方法时,应使用
()
表示优先级。例如:

$bar = new ( $foo->callBar() )  ();
//           ^^ expression      ^^ optional parentheses
相关的:
    new         $foo->callBar     ()
//  ^^ keyword  ^^ name           ^^ optional parentheses
$bar = new ( $foo->callBar() )  ();
//           ^^ expression      ^^ optional parentheses