Search code examples
phpnamespacesautoloaderphp-7.3

Cannot use namespace with autoloader


When using autoloader "spl_autoload_register" I cannot instantiate classes with namespace. It works fine to access class methods if not using namespace, or by simply excluding the autoloader. I have intentionally left out the namespace for the first class to show the error. All files are being run from same folder.

Potential reason for error:

Since the namespace works without autoloader I suspect that the autoloader adds the backslashes of the namespace path from the instantiation. If so, this might be the reason why the class is not found.

Observations:

Autoload loads classes without errors. Class methods can be accesses if not using namespace path during instantiation. If including the classes wihtout autoload it is possible to instantiate Class_2 with namespace.

If I comment-out the instantiation of Class_2, then I get following without errors:

Hello from class 1

Error message:

Hello from class 1PHP Fatal error:  Uncaught Error: Class 'Area_2\Class_2' not found in Xxx/run.php:9

Autoloader:

spl_autoload_register(
    function ($class_name) {

      $directories = ['./'];
      $extension   = ".class.php";

      foreach ( $directories as $dir) {
        if (file_exists($dir . $class_name . $extension)) {
            require_once($dir . $class_name . $extension);
            return;
        }
      }
    }
);

Run file:

include 'autoloader.php';

$class_1 = new Class_1();
$class_1->print_1();


$class_2 = new \Area_2\Class_2(); // Error by using namespace.
$class_2->print_2();

Class_1:

class Class_1 {

  public function print_1()
  {
    echo "Hello from class 1";
  }

}

Class_2:

namespace Area_2;

class Class_2 {

  public function print_2()
  {
    echo "Hello from class 2";
  }

}

Solution

  • Your autoloader is assuming a directory-based system for any classes that use a namespace, even if it isn't intended. The reason is that the namespace separator is the same as the directory separator (or similar enough that systems automatically convert between the two).

    When you do this:

    file_exists($dir . $class_name . $extension)

    Using the class Area_2\Class_2, PHP converts that to ./Area_2\Class_2.class.php.

    For this reason, your code expects folders.