If you like to declare an __autoload function within a namespace or class, use the spl_autoload_register() function to register it and it will work fine.
Правила разрешения имен
(PHP 5 >= 5.3.0)
Для этих правил здесь приведены несколько важных определений:
-
Определения имени пространства имен
- Неполное имя
-
Это идентификатор без разделителя пространств имен, например, Foo
- Полное имя
-
Это идентификатор с разделителем пространств имен, например, Foo\Bar
- Абсолютное имя
-
Это идентификатор с разделителем пространств имен, который начинается с разделителя пространств имен, например, \Foo\Bar. Идентификатор namespace\Foo также является абсолютным именем.
Имена разрешаются согласно следующим правилам:
- Вызовы абсолютных функций, классов или констант разрешаются во время компиляции. Например, new \A\B разрешается в класс A\B.
- Все неполные и полные имена (не абсолютные) переводятся в процессе компиляции в соответствии с текущими правилами импорта. Например, если пространство имен A\B\C заимпортировано как C, вызов C\D\e() преобразуется к A\B\C\D\e().
- Внутри пространства имен все полные имена, не переведенные в соответствии с правилами импорта, получают префикс текущего пространства имен. Например, если происходит вызов C\D\e(), он преобразуется внутри пространства имен A\B к A\B\C\D\e().
- Неполные имена классов преобразуются в процессе компиляции в соответствии с текущими правилами импорта (полное имя заменено на короткое импортируемое имя). Например, если пространство имен A\B\C заимпортировано как C, выражение new C() преобразовывается к выражению new A\B\C().
-
Внутри пространства имен (скажем, A\B), вызовы к неполным именам функций преобразуются
во время исполнения. Вот, к примеру, как преобразуется вызов
функции foo():
- Производится поиск функции из текущего пространства имен: A\B\foo().
- PHP пытается найти и вызвать функцию глобального пространства foo().
-
Внутри пространства имен (скажем, A\B), вызовы к неполным или полным
именам классов (неабсолютным)
преобразуются во время исполнения. Вот как выражение
new C() или new D\E() преобразуется.
Для new C():
- Ищется класс из текущего пространства имен: A\B\C.
- Производится попытка автозагрузки A\B\C.
- Ищется класс с помощью префиксации текущего пространства имен: A\B\D\E.
- Производится попытка автозагрузки A\B\D\E.
Пример #1 Примеры разрешения имен
<?php
namespace A;
use B\D, C\E as F;
// вызовы функций
foo(); // сперва пытается вызвать "foo", определенную в пространстве имен "A",
// затем вызывает глобальную функцию "foo"
\foo(); // вызывает функцию "foo", определенную в глобальном пространстве
my\foo(); // вызывает функцию "foo", определенную в пространстве "A\my"
F(); // сперва пытается вызвать "F", определенную в пространстве имен "A",
// затем вызывает глобальную функцию "F"
// ссылки на классы
new B(); // создает объект класса "B", определенного в пространстве имен "A".
// если не найден, то пытается сделать автозагрузку класса "A\B"
new D(); // используя правила импорта, создает объект класса "D", определенного в пространстве имен "B"
// если не найден, то пытается сделать автозагрузку класса "B\D"
new F(); // используя правила импорта, создает объект класса "E", определенного в пространстве имен "C"
// если не найден, то пытается сделать автозагрузку класса "C\E"
new \B(); // создает объект класса "B", определенного в глобальном пространстве,
// если не найден, то пытается сделать автозагрузку класса "B"
new \D(); // создает объект класса "D", определенного в глобальном пространстве,
// если не найден, то пытается сделать автозагрузку класса "D"
new \F(); // создает объект класса "F", определенного в глобальном пространстве,
// если не найден, то пытается сделать автозагрузку класса "F"
// статические методы/функции пространства имен из другого пространства имен
B\foo(); // вызывает функцию "foo" из пространства имен "A\B"
B::foo(); // вызывает метод "foo" из класса "B", определенного в пространстве имен "A"
// если класс "A\B" не найден, то пытается сделать автозагрузку класса "A\B"
D::foo(); // используя правила импорта, вызывает метод "foo" класса "D", определенного в пространстве имен "B"
// если класс "B\D" не найден, то пытается сделать автозагрузку класса "B\D"
\B\foo(); // вызывает функцию "foo" из пространства имен "B"
\B::foo(); // вызывает метод "foo" класса "B" из глобального пространства
// если класс "B" не найден, то пытается сделать автозагрузку класса "B"
// статические методы/функции пространства имен из текущего пространства имен
A\B::foo(); // вызывает метод "foo" класса "B" из пространства имен "A\A"
// если класс "A\A\B" не найден, то пытается сделать автозагрузку класса "A\A\B"
\A\B::foo(); // вызывает метод "foo" класса "B" из пространства имен "A"
// если класс "A\B" не найден, то пытается сделать автозагрузку класса "A\B"
?>
kdimi
27-Oct-2010 06:35
safakozpinar at NOSPAM dot gmail dot com
22-Oct-2010 01:04
As working 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
namespace Glue {
/**
* Define your custom structure and algorithms
* for autoloading in this class.
*/
class Import
{
public static function load ($classname)
{
echo 'Autoloading class '.$classname."\n";
require_once $classname.'.php';
}
}
}
/**
* Define function __autoload in global namespace.
*/
namespace {
function __autoload ($classname)
{
GlueImport::load($classname);
}
}
?>
sammaye
12-Jun-2010 04:24
I have noticed one problem with __autoload function. Say you have two namespaces, one is a sub of the other:
\Glue
\Glue\Import
Within that Import namespace you have a function auto() with the magic __autoload inside. No matter what you do that auto() will never traverse it's sub function meaning you will nevber get an __autoload function.
Even if you put the __autoload within a class within the namespace as such:
<?php
namespace GlueImport;
class import{
private static $_AutoLoad = array();
private static $_Imported = array();
function load($sName){
if(! isset(self::$_AutoLoad[$sName]))
//throw new ImportError("Cannot import module with name '$sName'.");
echo("file with name '$sName' failed to load with path '".self::$_AutoLoad[$sName]."'");
if(! isset(self::$_Imported[$sName])){
self::$_Imported[$sName] = True;
return include_once(self::$_AutoLoad[$sName]);
}
}
function push($sName, $sPath){
self::$_AutoLoad[$sName] = $sPath;
}
function auto(){
function __autoload($sClass){
load($sClass);
}
}
}
?>
It will not work. Just something to keep in mind.
rangel
31-Jul-2009 12:48
The term "autoload" mentioned here shall not be confused with __autoload function to autoload objects. Regarding the __autoload and namespaces' resolution I'd like to share the following experience:
->Say you have the following directory structure:
- root
| - loader.php
| - ns
| - foo.php
->foo.php
<?php
namespace ns;
class foo
{
public $say;
public function __construct()
{
$this->say = "bar";
}
}
?>
-> loader.php
<?php
//GLOBAL SPACE <--
function __autoload($c)
{
require_once $c . ".php";
}
class foo extends nsfoo // ns\foo is loaded here
{
public function __construct()
{
parent::__construct();
echo "<br />foo" . $this->say;
}
}
$a = new nsfoo(); // ns\foo also loads ns/foo.php just fine here.
echo $a->say; // prints bar as expected.
$b = new foo; // prints foobar just fine.
?>
If you keep your directory/file matching namespace/class consistence the object __autoload works fine.
But... if you try to give loader.php a namespace you'll obviously get 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!
rangel
31-Jul-2009 12:47
The term "autoload" mentioned here shall not be confused with __autoload function to autoload objects. Regarding the __autoload and namespaces' resolution I'd like to share the following experience:
->Say you have the following directory structure:
- root
| - loader.php
| - ns
| - foo.php
->foo.php
<?php
namespace ns;
class foo
{
public $say;
public function __construct()
{
$this->say = "bar";
}
}
?>
-> loader.php
<?php
//GLOBAL SPACE <--
function __autoload($c)
{
require_once $c . ".php";
}
class foo extends nsfoo // ns\foo is loaded here
{
public function __construct()
{
parent::__construct();
echo "<br />foo" . $this->say;
}
}
$a = new nsfoo(); // ns\foo also loads ns/foo.php just fine here.
echo $a->say; // prints bar as expected.
$b = new foo; // prints foobar just fine.
?>
If you keep your directory/file matching namespace/class consistence the object __autoload works fine.
But... if you try to give loader.php a namespace you'll obviously get 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!
