Reglas de resolución de nombres

(PHP 5 >= 5.3.0, PHP 7, PHP 8)

En el contexto de las reglas de resolución, hay varias definiciones importantes:

Definiciones para espacios de nombres
nombre no calificado

Esto es un identificador que no contiene un separador de espacio de nombres. Por ejemplo: Foo

nombre calificado

Esto es un identificador que contiene un separador de espacio de nombres. Por ejemplo: Foo\Bar

Nombre absoluto

Esto es un identificador que comienza con un separador de espacio de nombres. Por ejemplo: \Foo\Bar. El espacio de nombres Foo también es un nombre absoluto.

Nombre Relativo

Es un identificador que comienza con namespace, como namespace\Foo\Bar.

Los nombres se resuelven siguiendo las siguientes reglas:

  1. Los nombres absolutos siempre se traducen a nombres sin el separador de namespace. Por ejemplo, \A\B se traduce a A\B.
  2. Todos los nombres que no son absolutos se traducen con namespace reemplazado por el namespace actual. Si el nombre aparece en el namespace global, el prefijo namespace\ se elimina. Por ejemplo namespace\A en el namespace X\Y se traduce a X\Y\A. El mismo nombre en el namespace global se traduce a A.
  3. Para los nombres absolutos, el primer segmento se traduce de acuerdo con la clase/namespace de la tabla de importación. Por ejemplo, si el namespace A\B\C se importa como C, el nombre C\D\E se traduce a A\B\C\D\E.
  4. Para los nombres absolutos, si ninguna regla de importación se aplica, el namespace actual se prefiere al nombre. Por ejemplo, el nombre C\D\E en el namespace A\B, se traduce a A\B\C\D\E.
  5. Para los nombres absolutos, el nombre se traduce en relación con la tabla actual de importación para el tipo de símbolo respectivo. Esto significa que un nombre que se asemeja a una clase se traduce de acuerdo con la tabla de importación de class/namespace, los nombres de funciones utilizando la tabla de importación de funciones, y las constantes utilizando la tabla de importación de constantes. Por ejemplo, después use A\B\C; un uso como new C() corresponde al nombre A\B\C(). De manera similar, después de use function A\B\foo; un uso como foo() corresponde al nombre A\B\foo.
  6. Para los nombres relativos, si ninguna regla se aplica, y el nombre hace referencia a una clase, el namespace actual sirve como prefijo. Por ejemplo new C() en el namespace A\B corresponde al nombre A\B\C.
  7. Para los nombres relativos, si ninguna regla se aplica, y el nombre hace referencia a una función o constante, y el código está fuera del namespace global, el nombre se resuelve durante la ejecución. Supongamos que el código está en el namespace A\B, aquí es cómo se resuelve una llamada a la función foo():
    1. Busca una función en el espacio de nombres actual: A\B\foo().
    2. Intenta encontrar y llamar a la función global foo().

Ejemplo #1 Ejemplos de resolución de espacios de nombres

<?php
namespace A;
use
B\D, C\E as F;

// llamadas de funciones

foo(); // intenta llamar a la función "foo" en el espacio de nombres "A"
// luego llama a la función global "foo"

\foo(); // llama a la función "foo" definida en el espacio de nombres global

my\foo(); // llama a la función "foo" definida en el espacio de nombres "A\my"

F(); // intenta llamar a la función "F" definida en el espacio "A"
// luego intenta llamar a la función global "F"

// referencias de clases

new B(); // crea un objeto de la clase "B" definida en el espacio de nombres "A"
// si no se encuentra, intenta el autocargado en la clase "A\B"

new D(); // crea un objeto de la clase "D" definida en el espacio de nombres "B"
// si no se encuentra, intenta el autocargado en la clase "B\D"

new F(); // crea un objeto de la clase "E" definida en el espacio de nombres "C"
// si no se encuentra, intenta el autocargado en la clase "C\E"

new \B(); // crea un objeto de la clase "B" definida en el espacio de nombres global
// si no se encuentra, intenta el autocargado en la clase "B"

new \D(); // crea un objeto de la clase "D" definida en el espacio de nombres global
// si no se encuentra, intenta el autocargado en la clase "D"

new \F(); // crea un objeto de la clase "F" definida en el espacio de nombres global
// si no se encuentra, intenta el autocargado en la clase "F"

// métodos estáticos y funciones de espacio de nombres de otro espacio

B\foo(); // llama a la función "foo" del espacio de nombres "A\B"

B::foo(); // llama al método "foo" de la clase "B" definida en el espacio de nombres "A"
// si la clase "A\B" no se encuentra, intenta el autocargado en la clase "A\B"

D::foo(); // llama al método "foo" de la clase "D" definida en el espacio de nombres "B"
// si la clase "B\D" no se encuentra, intenta el autocargado en la clase "B\D"

\B\foo(); // llama a la función "foo" del espacio de nombres "B"

\B::foo(); // llama al método "foo" de la clase "B" ubicada en el espacio de nombres global
// si la clase "B" no se encuentra, intenta el autocargado en la clase "B"

// métodos estáticos y funciones de espacio de nombres del espacio actual

A\B::foo(); // llama al método "foo" de la clase "B" del espacio de nombres "A\A"
// si la clase "A\A\B" no se encuentra, intenta el autocargado en la clase "A\A\B"

\A\B::foo(); // llama al método "foo" de la clase "B" del espacio de nombres "A"
// si la clase "A\B" no se encuentra, intenta el autocargado en la clase "A\B"
?>
add a note

User Contributed Notes 7 notes

up
37
kdimi
14 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
33
rangel
15 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
safakozpinar at NOSPAM dot gmail dot com
14 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
0
Kavoir.com
11 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
-2
llmll
10 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
-5
rangel
15 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
anrdaemon at freemail dot ru
9 years 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');
?>
To Top