How to Use PHP Namespaces With Autoload

How do I use PHP namespaces with autoload?

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();

PHP's use Keyword and Autoloading

1) The class is autoloaded when you perform a new Class() statement.

2) see 1)

3) Which pattern is best to follow and why?:

I'd recommend to use use because you might get into a situation where you have really long namespaces and your code will become unreadable.

From the php docs:

This example attempts to load the classes MyClass1 and MyClass2 from
the files MyClass1.php and MyClass2.php respectively.

<?php
spl_autoload_register(function ($class_name) {
include $class_name . '.php';
});

$obj = new MyClass1();
$obj2 = new MyClass2();
?>

Namespaces are only an additional feature to organize classes.

EDIT: As @IMSoP pointed out in the comments, new is not the only time the autoloader is triggered. Accessing a class constant, static method, or static property will also trigger it, as will running class_exists.

PHP Autoload Classes Is Not Working With Namespaces

As already pointed out in the comments, you'll need to strip everything besides the class name, like so:

$classname = substr($classname, strrpos($classname, "\\") + 1);

Within the context of your autoloading function:

spl_autoload_register(function($classname){

$classname = substr($classname, strrpos($classname, "\\") + 1);
require_once "src/{$classname}.php";
});

Let's take this a step further by making use of the fact that an autoload function always receives the qualified namespace as opposed to, for example, the relative namespace:

<?php

namespace Acme;

$foo = new \Acme\Foo(); // Fully qualified namespace
$foo = new Acme\Foo(); // Qualified namespace
$foo = new Foo(); // Relative namespace

In all three instances, our autoload function is always given Acme\Foo as argument. With this in mind, it's fairly easy to implement an autoloader strategy that maps a namespace and any sub-namespaces to a file system path - especially if we include the top-level namespace (Acme, in this case) in the filesystem hierarchy.

For example, given these two classes within some project of ours...

<?php

namespace Acme;

class Foo {}

Foo.php

<?php

namespace Acme\Bar;

class Bar {}

Bar.php

...within this file system layout...

my-project
`-- library
`-- Acme
|-- Bar
| `-- Bar.php
`-- Foo.php

...we could implement a simple mapping between a namespaced class and its physical location like so:

<?php

namespace Acme;

const LIBRARY_DIR = __DIR__.'/lib'; // Where our classes reside

/**
* Autoload classes within the current namespace
*/
spl_autoload_register(function($qualified_class_name) {

$filepath = str_replace(

'\\', // Replace all namespace separators...
'/', // ...with their file system equivalents
LIBRARY_DIR."/{$qualified_class_name}.php"
);

if (is_file($filepath)) {

require_once $filepath;
}
});

new Foo();
new Bar\Bar();

Also note that you can register multiple autoloading functions, for example, to handle different top-level namespaces in different physical locations. In a real-word project, though, you might want to get yourself acquainted with Composer's autoloading mechanism:

  • https://getcomposer.org/doc/01-basic-usage.md#autoloading
  • https://getcomposer.org/doc/04-schema.md#autoload
  • https://getcomposer.org/doc/articles/autoloader-optimization.md

At some point, you might also want to have a look into PHP's autoloading specification:

  • https://www.php-fig.org/psr/psr-4/

PHP autoload with namespaces do not load file

Change your autoload code a little

<?php
spl_autoload_register( function( $class ) {

$folder = 'include/';
$prefix = '.class';
$ext = '.php';
//replace the backslash
$fullPath = $folder . str_replace( "\\", '/', $class ) . $prefix . $ext;

if( !file_exists( $fullPath ) ){
print 'Class file not found!';
return false;
}

require_once $fullPath;
});
?>

Namespace using composer autoload in PHP

In your composer.json

"Blog\\": "app/classes/Database" 

should be

"Blog\\": "app" 

as the namespace acts as the path to find the class

PHP Autoloading in Namespaces

Here's the only right answer.

Every namespace needs its own spl_autoload_register() function.

also, spl_autoload_register() syntax changed in 5.3:

spl_autoload_register(__NAMESPACE__ . "\\className::functionName"));

The following should work:

namespace glue;

require_once 'import.php';

use glue\import as import;
use glue\core\router as router;

$import = new import();

spl_autoload_register(__NAMESPACE__ . "\\$import::load"));

/** Works and echos glue\router **/
$router = new router();

/** Don't do nothing **/
$cheese = \glue\common\is_email($email);

Here is some live code that Just works!

in ../WebPageConsolidator.inc.php:

class WebPageConsolidator
{
public function __construct() { echo "PHP 5.2 constructor.\n"; }
}

in test.php:

<?php

namespace WebPage;

class MyAutoloader
{
public static function load($className)
{
require '../' . __NAMESPACE__ . $className . '.inc.php';
}
}

spl_autoload_register(__NAMESPACE__ . "\\MyAutoloader::load");

class Consolidator extends \WebpageConsolidator
{
public function __construct()
{
echo "PHP 5.3 constructor.\n";

parent::__construct();
}
}

// Output:
// PHP 5.3 constructor.
// PHP 5.2 constructor.

So I know it works.



Related Topics



Leave a reply



Submit