Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating object from variable using Namespaces and Autoload in PHP

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

like image 239
Jose Armesto Avatar asked Oct 30 '11 20:10

Jose Armesto


2 Answers

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();
like image 139
kgilden Avatar answered Oct 23 '22 19:10

kgilden


Name-spacing means that not only will PHP be able to find the file with the given path (pretty much the same as a require_once), but the class name actually matches the name-space directive as well. The only diff? Slashes for underscores (Example #2 below).

// This may be working because Symfony's autoloader has found a class named Index
$controller      = new Index(); 

// A name-space call so PHP knows where to actually find the file
// Chances are the class name here is Controller_Home_Index
$controller_name = "Controller\\Home\\Index";
$controller2     = new $controller_name();

// Symfony's autloader should have picked this up, but didn't
// It's possible that with this construct Symfony cannot find the class and b/c
// it's not namespaced, PHP has no choice but to fail
$controller_name = "Index";
$controller3     = new $controller_name();

Check your Symfony project cache directory, there are some flatfiles of PHP arrays that may help you as well.

like image 20
Mike Purcell Avatar answered Oct 23 '22 20:10

Mike Purcell