【问题标题】:instantiate a class from a variable in PHP?从 PHP 中的变量实例化一个类?
【发布时间】:2010-10-06 18:10:19
【问题描述】:

我知道这个问题听起来很模糊,所以我会用一个例子更清楚地说明:

$var = 'bar';
$bar = new {$var}Class('var for __construct()'); //$bar = new barClass('var for __construct()');

这就是我想做的。你会怎么做?我当然可以像这样使用 eval():

$var = 'bar';
eval('$bar = new '.$var.'Class(\'var for __construct()\');');

但我宁愿远离 eval()。没有 eval() 有没有办法做到这一点?

【问题讨论】:

    标签: php class variables eval


    【解决方案1】:

    先将类名放入变量中:

    $classname=$var.'Class';
    
    $bar=new $classname("xyz");
    

    这通常是您在工厂模式中看到的那种东西。

    更多详情请参阅Namespaces and dynamic language features

    【讨论】:

    • 我就是这样做的。请注意,在类中,您可以使用 parent 和 self。
    • 在类似的注释上,您也可以执行 $var = 'Name'; $obj->{'get'.$var}();
    • 好点,虽然这只适用于方法调用而不是构造函数
    • 如果您使用命名空间,请将当前命名空间放入字符串中:$var = __NAMESPACE__ . '\\' . $var . 'Class';
    • @basty - 但为什么呢?我只是花了太多时间弄清楚,为什么如果没有类名前面的命名空间,这将无法工作......
    【解决方案2】:
    class Test {
        public function yo() {
            return 'yoes';
        }
    }
    
    $var = 'Test';
    
    $obj = new $var();
    echo $obj->yo(); //yoes
    

    【讨论】:

    • 不,这不是一个很好的例子。仅当所有内容都在同一个 php 文件中时才有效。
    • 2ndGAB 应删除此评论。自动加载与这个问题无关。
    【解决方案3】:

    如何传递动态构造函数参数

    如果你想给类传递动态构造函数参数,你可以使用这段代码:

    $reflectionClass = new ReflectionClass($className);
    
    $module = $reflectionClass->newInstanceArgs($arrayOfConstructorParameters);
    

    More information on dynamic classes and parameters

    PHP >= 5.6

    从 PHP 5.6 开始,您可以使用 Argument Unpacking 进一步简化此操作:

    // The "..." is part of the language and indicates an argument array to unpack.
    $module = new $className(...$arrayOfConstructorParameters);
    

    感谢 DisgruntledGoat 指出这一点。

    【讨论】:

    • 从 PHP 5.6 开始,您应该能够使用参数解包:new $className(...$params)
    【解决方案4】:

    如果您使用命名空间

    在我自己的发现中,我认为值得一提的是您(据我所知)必须声明一个类的完整命名空间路径。

    MyClass.php

    namespace com\company\lib;
    class MyClass {
    }
    

    index.php

    namespace com\company\lib;
    
    //Works fine
    $i = new MyClass();
    
    $cname = 'MyClass';
    
    //Errors
    //$i = new $cname;
    
    //Works fine
    $cname = "com\\company\\lib\\".$cname;
    $i = new $cname;
    

    【讨论】:

    • 当需要使用命名空间创建时,唯一可行的解​​决方案是您的。感谢分享!
    • 但这很奇怪,为什么不使用声明的命名空间?
    • @YisraelDov 是的,这绝对是违反直觉的。但无论出于何种原因,它在这种情况下确实表现得很奇怪。谢谢 php
    • @YisraelDov 我想这是因为在这种情况下,从另一个命名空间实例化一个类会非常令人头疼。还要考虑变量可以传递。当类名作为文本写入 php 文件时,编写它的人确切地知道它写入的名称空间。但是当在函数之间传递变量时,跟进它将是一场噩梦。此外,如果您使用 get_class() ,它会返回 FQ 类名,以便可以立即将其存储在变量中并在任何地方使用。如果它依赖于文件的命名空间,它就不会很好地工作。
    【解决方案5】:

    我会推荐call_user_func()call_user_func_arrayphp 方法。 你可以在这里查看它们(call_user_func_arraycall_user_func)。

    例子

    class Foo {
    static public function test() {
        print "Hello world!\n";
    }
    }
    
     call_user_func('Foo::test');//FOO is the class, test is the method both separated by ::
     //or
     call_user_func(array('Foo', 'test'));//alternatively you can pass the class and method as an array
    

    如果您有要传递给方法的参数,请使用call_user_func_array() 函数。

    例子。

    class foo {
    function bar($arg, $arg2) {
        echo __METHOD__, " got $arg and $arg2\n";
    }
    }
    
    // Call the $foo->bar() method with 2 arguments
    call_user_func_array(array("foo", "bar"), array("three", "four"));
    //or
    //FOO is the class, bar is the method both separated by ::
    call_user_func_array("foo::bar"), array("three", "four"));
    

    【讨论】:

    • 此答案不适用于该问题。 OP 正在询问如何从变量字符串中实例化一个类(动态触发类 __construct 方法)并将 CLASS OBJECT 返回到一个新变量中——你的建议将返回你的类的值->method([ ])重新调用,而不是类对象,因此不适用于这种情况。查看返回值php.net/manual/en/function.call-user-func-array.php
    猜你喜欢
    • 2014-01-21
    • 2014-01-06
    • 1970-01-01
    • 1970-01-01
    • 2012-08-08
    • 2015-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多