PHP namespace and dynamic classname

2.9k views Asked by At

I've encountered a "weird" thing while experimenting with spl_autoload, namespaces and dynamic class names. I use PHP 5.3.2, call the autoload like this

set_include_path(get_include_path().PATH_SEPARATOR."classes".PATH_SEPARATOR."utils");
spl_autoload_extensions(".class.php");
spl_autoload_register();

Now to the core. Suggest following code:

new \User\Student;
$name="\User\Student";
new $name();

This works fine, file classes/user/student.class.php gets loaded successfully, both constructions succeed. However, a bit different usage:

$name="\User\Student";
new $name();
new \User\Student;

fails on "..Class \User\Student could not be loaded...". I suggest it should be related to the static/dynamic namespace resolution somehow. However, I don't think there should be any difference between these two except for the time they are processed at (compilation vs. runtime).

Thanks for any explanation.

1

There are 1 answers

0
DaveRandom On BEST ANSWER

The "problem" here is actually at a lower level than SPL, and can also be seen with __autoload(). This is best demonstrated in code:

function __autoload ($class) {
  echo "Loading $class\n";
}

new Test;
// displays "Loading Test"

$var = 'Test';
new $var;
// displays "Loading Test"

// However, when we introduce namespaces...

new \This\Is\A\Test;
// displays "Loading This\Is\A\Test"

$var = '\This\Is\A\Test';
new $var;
// displays "Loading \This\Is\A\Test"

Notice how when when introduce namespaces, the leading slash is not passed to the function when called statically, but it is when called dynamically.

The solution is therefore to do either of these fairly simple things:

  • Remove the leading slash from the dynamic class name instantiation.
  • Wrap the default spl_autoload() function like this:
set_include_path(get_include_path().PATH_SEPARATOR."classes".PATH_SEPARATOR."utils");
spl_autoload_extensions(".class.php");
spl_autoload_register(function($class) {
  spl_autoload(ltrim($class, '\\'));
});

Of course if you are doing this, you could also remove the call to spl_autoload_extensions() and just pass the ".class.php" string to the second argument of spl_autoload()