Creating object from variable using Namespaces and Autoload in PHP

Jose Armesto picture Jose Armesto · Oct 30, 2011 · Viewed 9.1k times · Source

EDIT with my own comment afterwards

I think the problem is that when PHP is parsing the file to "compile", first it translates class names to their fully qualified name. So Index will be translated to Controller\Home\Index. After that, is when PHP translates variables into their value. So if I use a variable as a class name, it won't qualified its name, because that step has already happened. And thats why is not finding the class. That's just a guess, but most likely it is that way Blockquote

End Edit

Im using UniversalClassLoader from Symfony2 project to auto load my classes, but I've found some strange error that I can't solve.

The auto loading thing is working fine, but then I ran into this problem:

$controller      = new Index(); // It works!

$controller_name = "Controller\\Home\\Index";
$controller2     = new $controller_name(); // It works!

$controller_name = "Index";
$controller3     = new $controller_name(); // Fatal error: Class 'Index' not found

The 2 first cases work just fine. In the first one, since Im using "use Controller\Home;" at the start of my script, I can use just "new Index();" without problems. But if instead of writing "Index", I use a string variable like $var = "Index", it does NOT work. I can't understand why. I need this script to be dynamic, thats why I need a variable for this.

Thank you!


additional long tail searches:

  • php fully qualified name from variable
  • php instantiate class from alias in variable

Answer

kgilden picture kgilden · Oct 31, 2011

Interesting question. By the looks of it, there's no way around it. The php docs seem to explicitly state this:

One must use the fully qualified name (class name with namespace prefix).

A possible workaround in your case would be to define a base namespace for your controllers in the configuration and registering the controllers by their relative namespace.

Suppose the base namespace is MyApp\Controller\ and we'd be holding our controllers in an array (for the sake of brevity):

$controllers = array(
    'foo/bar' => 'MyFooController',
    'baz'     => 'Foo\\MyBarController'
);

// One way how the controllers could be instantiated:

// returns 'MyApp\\Controller\\'
$namespace = $cfg->get('namespaces.controller');

$controller = $namespace.$controllers['baz'];
$controller = new $controller();