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?

2
  • Try use League\OAuth2\Client\Provider\Google as Google Commented Apr 5, 2016 at 16:46
  • @Xorifelse, nope, that's the same as what I have Commented Apr 5, 2016 at 16:56

2 Answers 2

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Yes, this is clear. But if the class file is loaded, OP can (try to) retrieve his complete name. +1 for your clarity/concision
And the "(try to)" is exactly the reason that approach is rather... suboptimal. :) Explicitly name the class by its full(ly qualified) name, period.
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.

9 Comments

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.
If you use autoload I think you don't have chances: how can php know what do you want?
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.
autoload is stock composer.
do you call require something/vendor/autoload.php; require something/vendor/autoload.php; ect... ?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.