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
How to Get First 5 Characters from String
Redirecting to Previous Page After Login - PHP
Why Is Pdo Better For Escaping MySQL Queries/Querystrings Than MySQL_Real_Escape_String
How to Get Enum Possible Values in a MySQL Database
Laravel Update Model With Unique Validation Rule For Attribute
How to Store File Name in Database, With Other Info While Uploading Image to Server Using PHP
How to Best Store User Information and User Login and Password
Simplify PHP Dom Xml Parsing - How
Simplexml and Print_R() - Why Is This Empty
What Does MySQL_Real_Escape_String() Do That Addslashes() Doesn'T
How Exactly Do Regular Expression Word Boundaries Work in PHP