从PHP中的变量实例化一个类?


146

我知道这个问题听起来很模糊,因此我将通过一个示例来使其更加清楚:

$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(),有没有办法做到这一点?

Answers:


213

首先将类名放入变量中:

$classname=$var.'Class';

$bar=new $classname("xyz");

这通常是您将以Factory模式包装的东西。

有关更多详细信息,请参见命名空间和动态语言功能


2
这就是我的方法。请注意,您可以在类中使用parent和self。
罗斯,

1
类似地,您也可以执行$ var ='Name';。$ obj-> {'get'。$ var}();
马里奥

1
好一点,尽管这仅适用于方法调用而不适用于构造函数
Paul Dixon

12
如果使用名称空间,则将当前名称空间放入字符串中:$var = __NAMESPACE__ . '\\' . $var . 'Class';
bastey

@bastey-但是为什么呢?我只是花了太多时间弄清楚,为什么没有类名之前没有名称空间,这将无法工作...
jkulak

72

如果您使用命名空间

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

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;

6
需要使用名称空间创建时,唯一可行的解​​决方案是您的。感谢分享!
TiagoGouvêa2015年

但这只是很奇怪,为什么不使用声明的名称空间呢?
伊斯雷尔·多夫

@YisraelDov是的,这绝对是反直观的。但是无论出于何种原因,它在这种情况下的表现都怪异的。谢谢php
csga5000 '18

@YisraelDov我猜是因为在这种情况下,从另一个名称空间实例化一个类会非常麻烦。还应考虑可以传递变量。当类名以文本形式写入php文件时,无论谁编写该类名,都确切知道它是在哪个名称空间中写入的。但是,当在函数之间传递变量时,对其进行跟踪将是一场噩梦。同样,如果使用get_class(),它将返回FQ类名,以便可以立即将其存储在变量中并在任何地方使用。如果它取决于文件的名称空间,那么它将无法很好地工作。
sbnc.eu

61

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

如果要将动态构造函数参数传递给类,则可以使用以下代码:

$reflectionClass = new ReflectionClass($className);

$module = $reflectionClass->newInstanceArgs($arrayOfConstructorParameters);

有关动态类和参数的更多信息

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指出这一点。


7
从PHP 5.6开始,您应该能够使用参数解包:new $className(...$params)
DisgruntledGoat 2015年

29
class Test {
    public function yo() {
        return 'yoes';
    }
}

$var = 'Test';

$obj = new $var();
echo $obj->yo(); //yoes

不,不是一个很好的例子。仅当所有内容都在同一个php文件中时才起作用。
fralbo

2
2ndGAB应该删除此评论。自动加载与此问题无关。
Jim Maguire

-1

我会推荐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"));

3
此答案不适用于该问题。OP正在询问如何从变量字符串中实例化一个类(动态触发类__construct方法)并将CLASS OBJECT返回到新变量中-您的建议将返回class-> method([])的值重新调用,而不是类对象,因此不适用于这种情况。参见返回值php.net/manual/en/function.call-user-func-array.php
ChrisN
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.