Initiating a class from string with extra step?

后端 未结 2 1885
梦毁少年i
梦毁少年i 2021-01-23 19:01

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 th

2条回答
  •  小鲜肉
    小鲜肉 (楼主)
    2021-01-23 19:28

    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
    

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

    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
    

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

    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
    

    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.

    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
    

提交回复
热议问题