用额外的步骤从字符串启动一个类? [英] Initiating a class from string with extra step?

查看:77
本文介绍了用额外的步骤从字符串启动一个类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I've been looking into substantiating a new class instance from a string in PHP. This is seems to be an acceptable procedure, however I am curious why it can't be done with the returns of a function call. I posted a short test below, and my results indicate it works if there is a variable intermediary (i.e. $bar = new $foo->callBar(); does not work, while $x = $foo->callBar(); $bar = new $x; does).

class Foo {
    function callBar() {
        return 'Bar';
    }
}
class Bar {
    function sayHi() {
        echo 'Hi';
    }
}

$foo = new Foo();
$bar = new $foo->callBar();




警告:未捕获错误:类名必须是有效对象或字符串

在php shell代码中:1堆栈跟踪:

#0 {main}在第1行的php shell代码中抛出

Warning: Uncaught Error: Class name must be a valid object or a string
in php shell code:1 Stack trace:
#0 {main} thrown in php shell code on line 1



$x = $foo->callBar();
$bar = new $x;
$bar->sayHi();
//Output: Hi

我很想知道为什么,或者我错了,这样做的正确原因是什么?

I'd love to know why that is, or if I'm wrong, what is the correct why of going about this?

推荐答案

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

As stated in the PHP Manual the new keyword accepts a string or an object as a class name. Optionally you can provide arguments to the constructor in parentheses at the end.

这意味着语法大致预期:

What this means is that the syntax roughly expects:

    new         [string|object]     ()
//  ^^ keyword  ^^ name             ^^ optional parentheses

另一个重要的事实是关键字 new 在所有运算符中具有最高的优先级。

Another important fact is that the keyword new has the highest precedence of all operators.

将这两个事实结合在一起意味着我们不能使用括号来使用 new 关键字来提高操作的优先级。如果我们使用括号,PHP将把它们视为 new 语法的可选部分。

Combining the two facts together means that we cannot use parentheses to increase the precedence of the operation with new keyword. If we use parentheses PHP will treat them as the optional part of new syntax. Something like this won't work.

$bar = new   ($foo->callBar());
//         ^ missing class name

没有明确的方法告诉PHP解析器以其他方式处理。

There is just no unambiguous way of telling PHP parser to treat this otherwise.

还有另一个需要记住的警告,爱德华·苏洛夫在回答中部分提及。类名可以来自任何变量,它是字符串或实例。

下面的代码将创建一个 Bar

There is also another caveat worth remembering, which Edward Surov has partially mentioned in his answer. The class name can come from any variable which is a string or an instance.
The following code will create an object of class Bar:

$obj = ['a'=>'Bar'];
$bar = new $obj['a'];
// or
$obj = (object) ['a'=>'Bar'];
$bar = new $obj->a;

所以,让我们解释一下代码的作用。

So, let's explain what your code does.

    new         $foo->callBar     ()
//  ^^ keyword  ^^ name           ^^ optional parentheses

因为您的 Foo 类没有属性 callBar ,它将触发Notice消息,但是PHP会检查它是否仍然可以用作类名。并且因为它不存在,所以它不能是字符串或实例,这就是您看到错误的原因。

Because your Foo class doesn't have a property callBar it will trigger Notice message, but PHP will check if it can be used as a class name anyway. And because it doesn't exist it can't be a string or an instance, which is why you see the error.

此问题已在PHP 8中修复 >。

变量语法调整RFC 解决了此问题。现在,您可以在创建类的实例时使用表达式。唯一要注意的是运算符优先级。调用函数/方法时,应使用()表示优先级。例如:

This has been fixed in PHP 8.
The Variable Syntax Tweaks RFC addressed this issue. Now you can use expressions when creating an instance of a class. The only thing to pay attention to is the operator precedence. When calling function/method you should use () to denote precedence. For example:

$bar = new ( $foo->callBar() )  ();
//           ^^ expression      ^^ optional parentheses

这篇关于用额外的步骤从字符串启动一个类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆