从别名命名空间中的字符串名称创建新的类实例


Create new class instance from string name in an aliased namespace

我看到过这样和这样的问题,但这两个问题都没有解决如果你已经有了一个名称空间,并且类在一个别名名称空间中,如何从字符串名称创建类实例:

<?php
namespace my'project;
require 'vendor/autoload.php';
//Example aliased classes, more may be defined elsewhere
use League'OAuth2'Client'Provider'Google;
use Stevenmaguire'OAuth2'Client'Provider'Microsoft;
//This is mapped from a submitted form value
$provider = 'Google';
$g = new $provider;

这将抛出PHP Fatal error: Class 'Google' not found。在这些问题中,它说你应该用__NAMESPACE__作为前缀,但问题是这些类不在my'project命名空间中,所以这也不起作用,因为它导致了my'project'Google的类名不存在。

对于这个特定代码,一个愚蠢的修复方法是使用一个数组来存储所有的名称空间和类名,但如果我事先不知道所有可能的类名,这就不起作用。

我甚至不知道如何使用反射来解决这个问题,因为出于同样的原因,我无法为别名类创建反射对象——new 'ReflectionClass($provider);抛出了同样的错误。

如何动态获取别名类名的命名空间?

您只需使用:

$provider = 'League'OAuth2'Client'Provider'Google';

没有其他解决方案,类名变量需要包含完全限定的类名;别名不适用于字符串类名,内省也不能帮助您。

命名空间的引入是为了在不同的上下文中允许相同的名称,所以答案是:不,这是不可能的。

您可以有一个类'League'OAuth2'Client'Provider'Google和另一个类'League'OAuth1'Client'Provider'Google:在这种情况下,如何确定要实例化哪个类?

假设您知道只有唯一的类名,则可以使用以下代码:

$provider = 'Google';
$found = False;
foreach( get_declared_classes() as $class )
{
    if( preg_match( "~(.*''')?($provider)$~", $class ) )
    {
        $found = $class;
        break;
    }
}
if( $found )
{
    $g = new ''''.$found;
}
else
{
    echo "No '$provider' class found";
}

带有DateTime类的演示

但这个例程只是"使用数组存储所有名称空间和类名"想法的简化,因为即使使用上面的代码,如果您不知道所有声明的类,也可能会获得不想要的结果。