İsim çözünürlük kuralları

İsim çözünürlük kurallarının amaçları gereği bazı önemli tanımlar:

İsim alanı adı tanımları
Nitelenmemiş isim

Fan gibi bir isim alanı ayracı içermeyen bir betimleyici.

Nitelenmiş isim

Fan\Fin gibi bir isim alanı ayracı içeren bir betimleyici.

Tamamen nitelenmiş isim

\Fan\Fin gibi bir isim alanı ayracı ile başlayan isim alanı ayraçlı bir betimleyici. namespace\Fan da tamamen nitelenmiş bir isimdir.

İsimler şu kurallara göre çözümlenir:

  1. Tamamen nitelenmiş işlev, sınıf ve sabit isimleri derleme sırasında çözümlenir. Örneğin, new \A\B deyimi A\B sınıfı olarak çözümlenir.
  2. Tamamen nitelenmemiş (nitelenmemiş ve nitelenmiş) isimlerin tamamı derleme sırasında geçerli ithal kurallarına göre dönüştürülür. Örneğin, A\B\C isim alanı C olarak ithal edilmişse bir C\D\e() çağrısı A\B\C\D\e() çağrısına dönüştürülür.
  3. Bir isim alanı içinde ithal kurallarına göre dönüştürülmeyen tüm nitelenmiş isimlerin önüne geçerli isim alanı ismi getirilir. Örneğin, A\B isim alanında yapılmış bir C\D\e() çağrısı A\B\C\D\e() çağrısına dönüştürülecektir.
  4. Nitelenmemiş sınıf isimleri derleme sırasında geçerli ithal kurallarına göre dönüştürülür (kısa ithal ismi için tam isim kullanılır). Örneğin, A\B\C isim alanı C olarak ithal edilmişse new C() deyimi new A\B\C() deyimine dönüştürülür.
  5. İsim alanı içindeki (A\B olsun), nitelenmemiş işlev çağrıları çalışma anında çözümlenir. fan() diye bir işlev şöyle çözümlenir:
    1. Geçerli isim alanında A\B\fan() işlevi aranır.
    2. Küresel fan() işlevi bulunmaya ve çağrılmaya çalışılır.
  6. İsim alanı içindeki (A\B olsun), nitelenmemiş (tamamen nitelenmemiş) veya nitelenmiş sınıf ismi çağrıları çalışma anında çözümlenir. new C() ve new D\E() deyimlerinin çözümlenişi aşağıda verilmiştir. new C() için:
    1. Geçerli isim alanında A\B\C sınıfı aranır.
    2. A\B\C özdevinimli olarak yüklenmeye çalışılır.
    new D\E() için:
    1. Geçerli isim alanı ile öncelenmiş olarak A\B\D\E sınıfı aranır.
    2. A\B\D\E özdevinimli olarak yüklenmeye çalışılır.
    Küresel isim alanındaki bir küresel sınıfa başvururken new \C() şeklinde tamamen nitelenmiş isim kullanılmalıdır.

Örnek 1 - Örneklerle İsim Çözünürlüğü

<?php
namespace A;
use 
B\DC\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ı özdevinimli 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ı özdevinimli 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ı özdevinimli olarak yüklenmeye çalışılır

new \B();   // Varsa küresel alanda tanımlı "B" örneklenir
            // yoksa "B" sınıfı özdevinimli olarak yüklenmeye çalışılır

new \D();   // Varsa küresel alanda tanımlı "D" örneklenir
            // yoksa "D" sınıfı özdevinimli olarak yüklenmeye çalışılır

new \F();   // Varsa küresel alanda tanımlı "F" örneklenir
            // yoksa "F" sınıfı özdevinimli olarak yüklenmeye çalışılır

// başka bir isim alanından duruk 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" özdevinimli 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"
            // özdevinimli 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" özdevinimli yüklenmeye çalışılır

// geçerli isim alanının duruk 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" özdevinimli
              // yüklenmeye çalışılır

\A\B::fan();  // "A\B" 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" özdevinimli yüklenmeye
              // çalışılır
?>
add a note add a note

User Contributed Notes 10 notes

up
16
kdimi
7 years ago
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.
up
14
rangel
8 years ago
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!
up
5
Kavoir.com
3 years ago
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".
up
4
safakozpinar at NOSPAM dot gmail dot com
7 years ago
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);
    }

}
?>
up
2
llmll
2 years ago
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.
up
1
CJ Taylor
3 years ago
It took me playing with it a bit  as I had a hard time finding documentation on when a class name matches a namespace, if that's even legal and what behavior to expect.  It IS explained in #6 but I thought I'd share this with other souls like me that see it better by example.  Assume all 3 files below are in the same directory.

file1.php
<?php
namespace foo;

class
foo {
  static function
hello() {
    echo
"hello world!";
  }
}
?>

file2.php
<?php
namespace foo;
include(
'file1.php');

foo::hello(); //you're in the same namespace, or scope.
\foo\foo::hello(); //called on a global scope.
?>

file3.php
<?php
include('file1.php');

foo\foo::hello(); //you're outside of the namespace
\foo\foo::hello(); //called on a global scope.
?>

Depending upon what you're building (example: a module, plugin, or package on a larger application), sometimes declaring a class that matches a namespace makes sense or may even be required.  Just be aware that if you try to reference any class that shares the same namespace, omit the namespace unless you do it globally like the examples above.

I hope this is useful, particularly for those that are trying to wrap your head around this 5.3 feature.
up
0
anrdaemon at freemail dot ru
1 year ago
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');
?>
up
-2
dn dot permyakov at gmail dot com
3 years ago
Can someone explain to me -  why do we need p.4 if we have p.2 (which covers both unqualified and qualified names)?
up
-3
rangel
8 years ago
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!
up
-4
StanE
2 years ago
What the name resolution rules do not say: Namespaces are case-insensitive.

You can write: namespace myframework\errorhandling;
Or: namespace MyFramework\ErrorHandling;

Same applies to namespaces after the "use" keyword or directly used qulified name namespaces in front of classes, functions or constants.
To Top