'Class not found when calling another class name in namespace

When I create a class object dynamically I don't understand why it throws class not found. However, if I will remove namespace App\Controls and use App\Controls\one, it worked perfectly example code:

namespace App\Controls;

use App\Controls\one;
    
class one {
    public static function test_one($className, $object) {
        return $object((new $className));
    }
}

class two {
    public function language($lang) {
        echo 'I love '.$lang;
    }
}


one::test_one('two', function($table) {
    $table->language('PHP');
});

from this structure I want to call class two depends on the value I input. I also include use App\Controls\two but still not working, but that's not the case because supposedly I will not add another use App\Controls\className just to call create another class object and it's not possible from PHP.

php


Solution 1:[1]

In PHP, namespaces are resolved when the code is compiled, not when it is run.

So, when you write this:

namespace MyNamespace;
use MyOthernamespace\SomeClass;

$foo = new Foo;
$bar = new SomeClass;

The compiler looks at the current namespace, and the class names you've "imported", and compiles the code as though you'd written this:

$foo = new MyNamespace\Foo;
$bar = new MyOthernamespace\SomeClass;

(Note that you don't need to use anything in the current namespace; that's assumed as the default prefix for everything.)

In your code, the compiler doesn't know that the 'two' is going to be used as a class name, so it doesn't change it; so when the dynamic code runs, it comes out literally as:

return $object((new two));

Which won't work - there isn't a class called two, only one called App\Controls\two.

The solution to this is the magic ::class syntax, which tells the compiler to expand something like it would for a class name, and then turn it into a string. It's important to know that despite the name, it doesn't actually care if the thing it's expanding is a class, or exists at all, it just expands it and assumes you know what you're doing with it.

So if you write this:

namespace App\Controls;

one::test_one(two::class, function($table) {
    $table->language('PHP');
});

It will be expanded by the compiler to this:

App\Controls\one::test_one('App\Controls\two', function($table) {
    $table->language('PHP');
});

Then when it gets into the dynamic code, it will be referencing the right class name, and run the code as though it was this:

return $object((new App\Controls\two));

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 IMSoP