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

时间:2016-04-05 16:31:28

标签: php namespaces

我已经看过像thisthis这样的问题,但是如果您已经有一个名称空间并且该类位于别名命名空间中,那么它们都没有说明如何从字符串名称创建类实例:

<?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。在这些问题中,它说你应该以{{1​​}}为前缀,但问题是这些类不在__NAMESPACE__命名空间中,因此它也不起作用,因为它会产生一个类名my\project并不存在。

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

我甚至无法看到如何使用反射来解决这个问题,因为我无法为相同的类创建反射对象,原因相同 - my\project\Google会抛出同样的错误。

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

2 个答案:

答案 0 :(得分:1)

您只需使用:

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

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

答案 1 :(得分:0)

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

您可以拥有一个类\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";
}

demo with DateTime class

但是这个例程只是简化你的想法“使用数组存储所有名称空间和类名”,因为 - 即使使用上面的代码 - 如果你不知道所有声明的类,你可以获得不受欢迎的结果。