Search code examples
phpnamespacesphp-5.3spl-autoload-register

PHP autoloader with namespaces


I am trying to understand how to define a working autoloader for a trivial application with namespaces.

I created following structure:

public
    index.php
src
    Models
        WordGenerator.php

Obviously, later it will grow. The WordGenerator.php file is following:

<?php
namespace Models;

class WordGenerator {
    public $filename;

    public function __construct($filename) {
        $this->_filename = $filename;
    }
}

Now I try to create instance of this object in index.php:

<?php
use \Models;

$wg = new WordGenerator("words.english");

Obviously I get fatal error because I did not define autoloader. However though, according to documentation all I can pass is $classname. How should I define the autoloader function to take namespace declared by use statement then??

[edit] I was wrong understood a moment ago. So here's my code for index.php:

spl_autoload_register(function ($className) {
    $className = ltrim($className, '\\');
    $prepend = "..\\src\\";
    $fileName  = "{$prepend}";
    $namespace = '';
    if ($lastNsPos = strrpos($className, '\\')) {
        $namespace = substr($className, 0, $lastNsPos);
        $className = substr($className, $lastNsPos + 1);
        $fileName  = $prepend.str_replace('\\', DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR;
    }
    $fileName .= str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';

    require $fileName;
});
//require '../src/Models/WordGenerator.php';

use Models;

$wg = new WordGenerator("words.english");
echo $wg->getRandomWord();

Now, this does not work and I get:

Warning: The use statement with non-compound name 'Models' has no effect in C:\xampp\htdocs\Hangman\public\index.php on line 22

Warning: require(..\src\WordGenerator.php): failed to open stream: No such file or directory in C:\xampp\htdocs\Hangman\public\index.php on line 16

Fatal error: require(): Failed opening required '..\src\WordGenerator.php' (include_path='.;C:\xampp\php\PEAR') in C:\xampp\htdocs\Hangman\public\index.php on line 16

However when I change new WordGenerator to new \Models\WordGenerator it works. Now, the question is: how can I pass namespaces declared by use statement to autoloader function to make it work properly?


Solution

  • Your use statement is incorrect. You want use Models\WordGenerator;

    The use operator doesn't declare anything but an alias. Consider the expanded form:

    use Models\WordGenerator as WordGenerator;
    

    Which is equivalent.


    You can alias a namespace rather than a class, but it doesn't work in the way you're attempting. For example:

    use Models as Foo;
    $wg = new Foo\WordGenerator("words.english");
    

    Would work. However:

    use Models;
    

    Is equivalent to:

    use Models as Models;
    

    Which effectively does nothing.


    For more information see Using namespaces: Aliasing/Importing in the PHP manual.