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, PHP 7, PHP 8)
İsim çözünürlük kurallarının amaçları gereği bazı önemli tanımlar:
Fan
gibi bir isim alanı ayracı içermeyen bir betimleyici.
Fan\Fin
gibi bir isim alanı ayracı içeren bir
betimleyici.
\Fan\Fin
gibi bir isim alanı ayracı ile başlayan isim
alanı ayraçlı bir betimleyici. \Fan
isim alanı da
tamamen nitelenmiş bir isimdir.
namespace\Fan\Fin
gibi namespace
ile
başlayan bit tanımlayıcıdır.
İsimler şu kurallara göre çözümlenir:
new \A\B
deyimi
A\B
sınıfı olarak çözümlenir.
namespace\
öneki geçerli
isim alanı ile değiştirilerek çözümlenir. Eğer isim küresel isim
alanındaysa namespace\
öneki konmaz. Örneğin,
X\Y
isim alanındaki namespace\A
,
X\Y\A
olarak çözümlenirken aynı isim küresel isim
alanı içindeyse A
olarak çözümlenir.
A\B\C
isim
alanı C
olarak ithal edilmişse
C\D\E
ismi A\B\C\D\E
ismine
dönüştürülür.
A\B
isim alanınındaki bir C\D\E
ismi A\B\C\D\E
ismine dönüştürülecektir.
use A\B\C;
sonrasında new C()
gibi bir kullanım A\B\C()
olarak çözümlenir. benzer
şekilde, use function A\B\fan;
sonrasında
fan()
gibi bir kullanım A\B\fan
ismine dönüştürülür.
A\B
isim alanındaki new C()
bildirimi
A\B\C
ismine çözümlenir.
A\B
isim alanında olduğunu
varsayalım, fan()
işlev çağrısı şöyle gerçekleşir:
A\B\fan()
işlevi aranır.
fan()
işlevi bulunmaya ve çağrılmaya çalışılır.
Örnek 1 - Örneklerle İsim Çözünürlüğü
<?php
namespace A;
use B\D, C\E as F;
// işlev çağrıları
fan(); // Varsa "A" isim alanında tanımlı "fan", yoksa küresel "fan"
\fan(); // Küresel alanda tanımlı "fan" çağrılır
my\fan(); // "A\my" isim alanında tanımlı "fan" çağrılır
F(); // Varsa "A" isim alanında tanımlı "F", yoksa küresel "F"
//sınıf adı çağrıları
new B(); // Varsa "A" isim alanında tanımlı "B" örneklenir
// Yoksa "A\B" sınıfı otomatik olarak yüklenmeye çalışılır
new D(); // ithal kuralları ile, "B" isim alanında tanımlı "D" örneklenir
// yoksa "B\D" sınıfı otomatik olarak yüklenmeye çalışılır
new F(); // ithal kuralları ile, "C" isim alanında tanımlı "E" örneklenir
// yoksa "C\E" sınıfı otomatik olarak yüklenmeye çalışılır
new \B(); // Varsa küresel alanda tanımlı "B" örneklenir
// yoksa "B" sınıfı otomatik olarak yüklenmeye çalışılır
new \D(); // Varsa küresel alanda tanımlı "D" örneklenir
// yoksa "D" sınıfı otomatik olarak yüklenmeye çalışılır
new \F(); // Varsa küresel alanda tanımlı "F" örneklenir
// yoksa "F" sınıfı otomatik olarak yüklenmeye çalışılır
// başka bir isim alanından statik yöntem/isim alanı işlevleri
B\fan(); // "A\B" isim alanında tanımlı "fan" çağrılır
B::fan(); // "A" isim alanında tanımlı "B" sınıfının "fan" yöntemi çağrılır
// "A\B" sınıfı yoksa, "A\B" otomatik yüklenmeye çalışılır
D::fan(); // ithal kuralları ile, "B" isim alanında tanımlı "D" sınıfının
// "fan" yöntemi çağrılır; "B\D" sınıfı yoksa, "B\D"
// otomatik yüklenmeye çalışılır
\B\fan(); // "B" isim alanında tanımlı "fan" çağrılır
\B::fan(); // Küresel alandaki "B" sınıfının "fan" yöntemi çağrılır
// "B" sınıfı yoksa, "B" otomatik yüklenmeye çalışılır
// geçerli isim alanının statik yöntemleri ve isim alanı işlevleri
A\B::fan(); // "A\A" isim alanında tanımlı "B" sınıfının "fan" yöntemi
// çağrılır; "A\A\B" sınıfı yoksa, "A\A\B" otomatik
// yüklenmeye çalışılır
\A\B::fan(); // "A" isim alanında tanımlı "B" sınıfının "fan" yöntemi
// çağrılır; "A\B" sınıfı yoksa, "A\B" otomatik yüklenmeye
// çalışılır
?>
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.
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 ns\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; // 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!
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)
{
\Glue\Import::load($classname);
}
}
?>
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".
The mentioned filesystem analogy fails at an important point:
Namespace resolution *only* works at declaration time. The compiler fixates all namespace/class references as absolute paths, like creating absolute symlinks.
You can't expect relative symlinks, which should be evaluated during access -> during PHP runtime.
In other words, namespaces are evaluated like __CLASS__ or self:: at parse-time. What's *not* happening, is the pendant for late static binding like 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 works as expected.
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 ns\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; // 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!
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 necessity.
Something like this should suffice for most times:
<?php
namespace org\example;
function spl_autoload($className)
{
$file = new \SplFileInfo(__DIR__ . substr(strtr("$className.php", '\\', '/'), 11));
$path = $file->getRealPath();
if(empty($path))
{
return false;
}
else
{
return include_once $path;
}
}
\spl_autoload_register('\org\example\spl_autoload');
?>