How do I use PHP namespaces with autoload?

136,379

Solution 1

Class1 is not in the global scope.

Note that this is an old answer and things have changed since the days where you couldn't assume the support for spl_autoload_register() which was introduced in PHP 5.1 (now many years ago!).

These days, you would likely be using Composer. Under the hood, this would be something along the lines of this snippet to enable class autoloading.

spl_autoload_register(function ($class) {
    // Adapt this depending on your directory structure
    $parts = explode('\\', $class);
    include end($parts) . '.php';
});

For completeness, here is the old answer:

To load a class that is not defined in the global scope, you need to use an autoloader.

<?php

// Note that `__autoload()` is removed as of PHP 8 in favour of 
// `spl_autoload_register()`, see above
function __autoload($class)
{
    // Adapt this depending on your directory structure
    $parts = explode('\\', $class);
    require end($parts) . '.php';
}

use Person\Barnes\David as MyPerson;

$class = new MyPerson\Class1();

or without aliases:

use Person\Barnes\David\Class1;

$class = new Class1();

Solution 2

As mentioned Pascal MARTIN, you should replace the '\' with DIRECTORY_SEPARATOR for example:

$filename = BASE_PATH . DIRECTORY_SEPARATOR . str_replace('\\', DIRECTORY_SEPARATOR, $class) . '.php';
include($filename);

Also I would suggest you to reorganize the dirrectory structure, to make the code more readable. This could be an alternative:

Directory structure:

ProjectRoot
 |- lib

File: /ProjectRoot/lib/Person/Barnes/David/Class1.php

<?php
namespace Person\Barnes\David
class Class1
{
    public function __construct()
    {
        echo __CLASS__;
    }
}
?>
  • Make the sub directory for each namespace you are defined.

File: /ProjectRoot/test.php

define('BASE_PATH', realpath(dirname(__FILE__)));
function my_autoloader($class)
{
    $filename = BASE_PATH . '/lib/' . str_replace('\\', '/', $class) . '.php';
    include($filename);
}
spl_autoload_register('my_autoloader');

use Person\Barnes\David as MyPerson;
$class = new MyPerson\Class1();
  • I used php 5 recomendation for autoloader declaration. If you are still with PHP 4, replace it with the old syntax: function __autoload($class)

Solution 3

Your __autoload function will receive the full class-name, including the namespace name.

This means, in your case, the __autoload function will receive 'Person\Barnes\David\Class1', and not only 'Class1'.

So, you have to modify your autoloading code, to deal with that kind of "more-complicated" name ; a solution often used is to organize your files using one level of directory per "level" of namespaces, and, when autoloading, replace '\' in the namespace name by DIRECTORY_SEPARATOR.

Solution 4

I do something like this: See this GitHub Example

spl_autoload_register('AutoLoader');

function AutoLoader($className)
{
    $file = str_replace('\\',DIRECTORY_SEPARATOR,$className);

    require_once 'classes' . DIRECTORY_SEPARATOR . $file . '.php'; 
    //Make your own path, Might need to use Magics like ___DIR___
}

Solution 5

I see that the autoload functions only receive the "full" classname - with all the namespaces preceeding it - in the following two cases:

[a] $a = new The\Full\Namespace\CoolClass();

[b] use The\Full\Namespace as SomeNamespace; (at the top of your source file) followed by $a = new SomeNamespace\CoolClass();

I see that the autoload functions DO NOT receive the full classname in the following case:

[c] use The\Full\Namespace; (at the top of your source file) followed by $a = new CoolClass();

UPDATE: [c] is a mistake and isn't how namespaces work anyway. I can report that, instead of [c], the following two cases also work well:

[d] use The\Full\Namespace; (at the top of your source file) followed by $a = new Namespace\CoolClass();

[e] use The\Full\Namespace\CoolClass; (at the top of your source file) followed by $a = new CoolClass();

Hope this helps.

Share:
136,379

Related videos on Youtube

David Barnes
Author by

David Barnes

I work as a Software Engineer in Minneapolis, Minnesota.

Updated on July 08, 2022

Comments

  • David Barnes
    David Barnes almost 2 years

    I get this error when I try to use autoload and namespaces:

    Fatal error: Class 'Class1' not found in /usr/local/www/apache22/data/public/php5.3/test.php on line 10

    Can anyone tell me what I am doing wrong?

    Here is my code:

    Class1.php:

    <?php
    
    namespace Person\Barnes\David
    {
        class Class1
        {
            public function __construct()
            {
                echo __CLASS__;
            }
        }
    }
    
    ?>
    

    test.php:

    <?php
    
    function __autoload($class)
    {
        require $class . '.php';
    }
    
    use Person\Barnes\David;
    
    $class = new Class1();
    
    ?>
    
  • David Barnes
    David Barnes over 14 years
    This is not what I found. When I did put the statement die($class); in the __autoload function, it printed out 'Class1"', not 'Person\Barnes\David\Class1'
  • tishma
    tishma about 11 years
    True. $class parameter of autoload is the class name as written in constructor call.
  • cartbeforehorse
    cartbeforehorse over 10 years
    You don't have to use AS. That's not why this solution works. You could just as easily do: use Person\Barnes\David\Class1; (which is equivalent to use Person\Barnes\David\Class1 as Class1;).
  • user345602
    user345602 about 10 years
    Thanks ,this works. But I cant understand why we can just use $class = new Class1(); when we have already defined "use Person\Barnes\David; " before ?
  • Justin C
    Justin C about 10 years
    @user346665 you must use use Person\Barnes\David\Class1; in order to do $class = new Class1();. With use Person\Barnes\David; you must do $class = new David\Class1();. The use keyword by itself is the equivalent of use Person\Barnes\David\Class1 as Class1; or use Person\Barnes\David as David;, respectively for each example.
  • Mark Amery
    Mark Amery over 9 years
    Downvote for "Your __autoload function will receive the full class-name, including the namespace name" - this is only true if you have explicitly used the class you're trying to reference, not if you've merely used the namespace it belongs to. The OP's mistake was that he'd used the namespace containing a class and was then expecting his autoload function to magically get passed the full classpath somehow. This answer doesn't really address the OP's mistake.
  • Andrew Larsson
    Andrew Larsson about 9 years
    As a side note, the use keyword doesn't work properly in the PHP interactive command-line interface (php --interactive);
  • dennis
    dennis almost 9 years
    Nice and simple. If one should be looking for that .)
  • Itay Moav -Malimovka
    Itay Moav -Malimovka about 8 years
    as a side note, str_replace ([ '_','\\'] '/', $className ); is twice as fast than two str_replace
  • Mike
    Mike over 7 years
    As long as it doesn't matter if the php file is upper/lower cased, the directories still remain case sensisive
  • Ethan
    Ethan almost 6 years
    While this code may answer the question, providing additional context regarding why and/or how this code answers the question improves its long-term value.
  • Bruno de Oliveira
    Bruno de Oliveira over 5 years
    For those reading in 2018, use @prince-billy-graham solution with spl_autoload_register