18

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

Sebastian Mach
  • 38,570
  • 8
  • 95
  • 130
Jose Armesto
  • 12,794
  • 8
  • 51
  • 56
  • Do you have a `namespace` or `use` declaration at the top of your script? That is probably why `new Index()` works. –  Oct 30 '11 at 20:33
  • Yep, I do. Thats why it works the first case, but I want the third case to work aswell. How do I do? – Jose Armesto Oct 30 '11 at 20:40
  • My guess is PHP only uses the `use` clause when locating unqualified symbols and not strings. Looks like you'll need to specify the full name in the string, ie `$controller_name = '\Controller\Home\Index';` – Phil Oct 30 '11 at 22:29
  • 4
    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. – Jose Armesto Oct 30 '11 at 22:38

3 Answers3

7

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();
kgilden
  • 10,336
  • 3
  • 50
  • 48
2

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.

Mike Purcell
  • 19,847
  • 10
  • 52
  • 89
0

Have you tried:

use Controller\Home\Index as Index;

and then

$controller3 = new Index();

is the same thing as happened to me with Zend's amazon S3 Service. I resolved it using:

use Zend\Service\Amazon\S3\S3 as Zend_Service_Amazon_S3;

$s3 = new Zend_Service_Amazon_S3($key, $secret);

Of course, after namespacing it in the autoload file as:

'Zend'                => __DIR__.'/../vendor/Zend/library',
Cristian Douce
  • 3,148
  • 1
  • 16
  • 17