1

I've seen questions like this and this, but neither addresses how to create a class instance from a string name if you already have a namespace and the class is 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;

This throws PHP Fatal error: Class 'Google' not found. In those questions, it says you should prefix with __NAMESPACE__, but the problem is that these classes are not in the my\project namespace so that doesn't work either, because it results in a class name of my\project\Google which doesn't exist.

A dumb fix for this specific code would be to use an array to store all the namespaces and class names, but that can't work if I don't know all possible class names in advance.

I can't even see how to use reflection to solve this because I can't create a reflection object for the aliased class for the same reason - new \ReflectionClass($provider); throws the same error.

How can I get the namespace of an aliased class name dynamically?

Community
  • 1
  • 1
Synchro
  • 35,538
  • 15
  • 81
  • 104

2 Answers2

1

You will simply have to use:

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

There is no other solution, class name variables need to contain the fully qualified class name; aliasing doesn't apply to string class names, and introspection can't help you either.

deceze
  • 510,633
  • 85
  • 743
  • 889
  • Yes, this is clear. But if the class file is loaded, OP can (try to) retrieve his complete name. +1 for your clarity/concision – fusion3k Apr 05 '16 at 21:40
  • And the "(try to)" is exactly the reason that approach is rather... suboptimal. :) Explicitly name the class by its full(ly qualified) name, period. – deceze Apr 06 '16 at 05:19
0

Namespaces are introduced to allow same names in different contexts, so the answer is: no, it is not possible.

You can have a class \League\OAuth2\Client\Provider\Google and another class \League\OAuth1\Client\Provider\Google: in this case, how you can determine what class to instantiate?

Assuming you know that there are only unique class names, you can use this code:

$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

but this routine is only a simplification of your idea “to use an array to store all the namespaces and class names”, because — even with above code — if you don't know all declared classes, you can obtain unwanted results.

fusion3k
  • 11,568
  • 4
  • 25
  • 47
  • Thanks. There are further twists to this - autoloaded classes won't be in the `get_declared_classes` list yet, and having a `use` statement does not necessarily imply that a class exists - that only matters when you try to instantiate it. – Synchro Apr 05 '16 at 17:02
  • If you use autoload I think you don't have chances: how can php know what do you want? – fusion3k Apr 05 '16 at 17:09
  • It does know what I want! If I use the aliased class name explicitly, `$a = new Google;`, it works fine. I think this is possibly a PHP bug - class name resolution seems to be not quite in the right order. – Synchro Apr 05 '16 at 17:14
  • autoload is stock composer. – Synchro Apr 05 '16 at 17:14
  • do you call `require something/vendor/autoload.php; require something/vendor/autoload.php; ect...` ? – fusion3k Apr 05 '16 at 17:48
  • No. I get the feeling you don't use composer. This isn't a class loading problem. – Synchro Apr 05 '16 at 17:54
  • Your solution is inside your autoloader – fusion3k Apr 05 '16 at 18:02
  • It's really not. I can cause the same issue without using an autoloader at all; the problem appears before any autoloader code is run, and static naming works perfectly. It's the naming that's the problem, not the loading. – Synchro Apr 05 '16 at 18:10
  • You are lost in a classic XY problem: your assumption fails, so you are fixed to it. But yes, your real problem is the class loading (this is your goal). When a class il loaded, you know how find its complete name, so you have to concentrate to it. – fusion3k Apr 05 '16 at 21:34