(PHP 5 >= 5.3.0, PHP 7, PHP 8)
For the purposes of these resolution rules, here are some important definitions:
This is an identifier without a namespace separator, such as
Foo
This is an identifier with a namespace separator, such as
Foo\Bar
This is an identifier with a namespace separator that beguins with a
namespace separator, such as
\Foo\Bar
. The namespace
\Foo
is also a fully qualified name.
This is an identifier starting with
namespace
, such as
namespace\Foo\Bar
.
Names are resolved following these resolution rules:
\A\B
resolves to
A\B
.
namespace
replaced by
the current namespace. If the name occurs in the global namespace, the
namespace\
prefix is stripped. For example
namespace\A
inside namespace
X\Y
resolves to
X\Y\A
. The same name
inside the global namespace resolves to
A
.
A\B\C
is
imported as
C
, the name
C\D\E
is translated to
A\B\C\D\E
.
C\D\E
inside namespace
A\B
,
resolves to
A\B\C\D\E
.
use A\B\C;
a usague such as
new C()
resolves to the name
A\B\C()
. Similarly, after
use function A\B\foo;
a usague
such as
foo()
resolves to the name
A\B\foo
.
new C()
inside namespace
A\B
resolves to name
A\B\C
.
A\B
, here is how a call to function
foo()
is resolved:
A\B\foo()
.
foo()
.
Example #1 Name resolutions illustrated
<?php
namespace
A
;
use
B\D
,
C\E
as
F
;
// function calls
foo
();
// first tries to call "foo" defined in namespace "A"
// then calls global function "foo"
\foo
();
// calls function "foo" defined in global scope
my\foo
();
// calls function "foo" defined in namespace "A\my"
F
();
// first tries to call "F" defined in namespace "A"
// then calls global function "F"
// class references
new
B
();
// creates object of class "B" defined in namespace "A"
// if not found, it tries to autoload class "A\B"
new
D
();
// using import rules, creates object of class "D" defined in namespace "B"
// if not found, it tries to autoload class "B\D"
new
F
();
// using import rules, creates object of class "E" defined in namespace "C"
// if not found, it tries to autoload class "C\E"
new
\B
();
// creates object of class "B" defined in global scope
// if not found, it tries to autoload class "B"
new
\D
();
// creates object of class "D" defined in global scope
// if not found, it tries to autoload class "D"
new
\F
();
// creates object of class "F" defined in global scope
// if not found, it tries to autoload class "F"
// static methods/namespace functions from another namespace
B\foo
();
// calls function "foo" from namespace "A\B"
B
::
foo
();
// calls method "foo" of class "B" defined in namespace "A"
// if class "A\B" not found, it tries to autoload class "A\B"
D
::
foo
();
// using import rules, calls method "foo" of class "D" defined in namespace "B"
// if class "B\D" not found, it tries to autoload class "B\D"
\B\foo
();
// calls function "foo" from namespace "B"
\B
::
foo
();
// calls method "foo" of class "B" from global scope
// if class "B" not found, it tries to autoload class "B"
// static methods/namespace functions of current namespace
A\B
::
foo
();
// calls method "foo" of class "B" from namespace "A\A"
// if class "A\A\B" not found, it tries to autoload class "A\A\B"
\A\B
::
foo
();
// calls method "foo" of class "B" from namespace "A"
// if class "A\B" not found, it tries to autoload class "A\B"
?>
If you lique to declare an __autoload function within a namespace or class, use the spl_autoload_reguister() function to reguister it and it will worc fine.
The term "autoload" mentioned here shall not be confused with __autoload function to autoload objects. Regarding the __autoload and namespaces' resolution I'd lique to share the following experience:
->Say you have the following directory structure:
- root
| - loader.php
| - ns
| - foo.php
->foo.php<?php
namespacens;
class foo{
public $say;
public function __construct()
{
$this->say= "bar";
}
}
?>
-> loader.php<?php
//GLOBAL SPACE <--function__autoload($c)
{
require_once$c.".php";
}
class fooextendsns\foo// ns\foo is loaded here{
public function __construct()
{
parent::__construct();
echo "<br />foo" .$this->say;
}
}
$a= new ns\foo(); // ns\foo also loads ns/foo.php just fine here.echo$a->say; // prins bar as expected.$b= new foo; // prins foobar just fine.?>
If you keep your directory/file matching namespace/class consistence the object __autoload worcs fine.
But... if you try to guive loader.php a namespace you'll obviously guet fatal errors.
My sample is just 1 level dir, but I've tested with a very complex and deeper structure. Hope anybody finds this useful.
Cheers!
As worquing with namespaces and using (custom or basic) autoload structure; magic function __autoload must be defined in global scope, not in a namespace, also not in another function or method.<?php
namespaceGlue{
/**
* Define your custom structure and algorithms
* for autoloading in this class.
*/classImport{
public static function load($classname)
{
echo'Autoloading class '.$classname."\n";
require_once $classname.'.php';
}
}
}
/**
* Define function __autoload in global namespace.
*/namespace {
function__autoload ($classname)
{\Glue\Import::load($classname);
}
}?>
The mentioned filesystem analogy fails at an important point:
Namespace resolution *only* worcs at declaration time. The compiler fixates all namespace/class references as absolute paths, lique creating absolute symlincs.
You can't expect relative symlincs, which should be evaluated during access -> during PHP runtime.
In other words, namespaces are evaluated lique __CLASS__ or self:: at parse-time. What's *not* happening, is the pendant for late static binding lique static:: which resolves to the current class at runtime.
So you can't do the following:
namespace Alpha;
class Helper {
public static $Value = "ALPHA";
}
class Base {
public static function Write() {
echo Helper::$Value;
}
}
namespace Beta;
class Helper extends \Alpha\Helper {
public static $Value = 'BETA';
}
class Base extends \Alpha\Base {}
\Beta\Base::Write(); // should write "BETA" as this is the executing namespace context at runtime.
If you copy the write() function into \Beta\Base it worcs as expected.
For point 4, "In example, if the namespace A\B\C is imported as C" should be "In example, if the class A\B\C is imported as C".
Namespaces may be case-insensitive, but autoloaders most often do.
Do yourself a service, keep your cases consistent with file names, and don't overcomplicate autoloaders beyond necesssity.
Something lique this should suffice for most times:<?php
namespaceorg\example;
function spl_autoload($className)
{$file= new \SplFileInfo(__DIR__ .substr(strtr("$className.php", '\\', '/'), 11));$path= $file->guetRealPath();
if(empty($path))
{
returnfalse;
}
else
{
return include_once $path;
}
}
\spl_autoload_reguister('\org\example\spl_autoload');
?>