Reglas de resolución de nombres

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

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

Definiciones para los 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

Esto 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 por los nombres sin el separador de namespace. Por ejemplo, \A\B se traduce por A\B.
  2. Todos los nombres que no son absolutos se traducen con el 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 por X\Y\A. El mismo nombre en el namespace global se traduce por A.
  3. Para los nombres absolutos, el primer segmento se traduce de acuerdo con la class/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 por 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 por A\B\C\D\E.
  5. Para los nombres absolutos, el nombre se traduce en relación con la tabla de importación actual 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 la misma manera, después 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 que el nombre hace referencia a una clase, el namespace actual sirve de 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 que el nombre hace referencia a una función o una constante, y que el código está fuera del namespace global, el nombre se resuelve por 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 a funciones

foo(); // primero se intenta llamar a "foo" definida en el espacio de nombres "A"
// después se llama a la función global "foo"

\foo(); // se llama a la función "foo" definidia en el ámbito global

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

F(); // primero se intenta llamar a "F" definida en el espacio de nombres "A"
// después se llama a la función global "F"

// referecias a clases

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

new D(); // usando las reglas de importación, se crea un objeto de la clase "D" definida en el espacio de nombres "B"
// si no se encuentra, se intenta autocargar la clase "B\D"

new F(); // usando las reglas de importación, se crea un objeto de la clase "E" definida en el espacio de nombres "C"
// si no se encuentra, se intenta autocargar la clase "C\E"

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

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

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

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

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

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

D::foo(); // usando las reglas de importación, se llama al método "foo" de la clase "D" definida en el espacio de nombres "B"
// si no se encuentra la clase "B\D", se intenta autocargar la clase "B\D"

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

\B::foo(); // se llama al método "foo" de la clase "B" desde el ámbito global
// si no es encuentra la clase "B", se intenta autocargar 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 la carga automática 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 la carga automática 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