PHP 8.1.31 Released!

P+F: cosas que es necesario saber sobre los espacios de nombres

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

Esta sección está dividida en dos subsecciones: preguntas comunes, y algunas especificaciones de implementación que son útiles para comprender completamente los espacios de nombres.

Primero, las preguntas comunes.

  1. Si no utilizo espacios de nombres, ¿debería preocuparme por algo de esto?
  2. ¿Cómo uso clases internas o globales en un espacio de nombres?
  3. ¿Cómo uso clases, funciones o constantes de espacios de nombres en su propio espacio de nombres?
  4. ¿Cómo se resuelve un nombre como \mi\nombre o \nombre?
  5. ¿Cómo se resuelve un nombre como mi\nombre?
  6. ¿Cómo se resuelve un nombre de clase no cualificado como nombre?
  7. ¿Cómo se resuelve un nombre de función o de constante no cualifcado como nombre?

Existen unos pocos detalles de las implementaciones de espacios de nombres que son útiles para enterderlos.

  1. Importar nombres no entra en conflicto con las clases definidas en el mismo fichero.
  2. Los espacios de nombres anidados no están permitidos.
  3. Antes de PHP 5.6, ni las funciones ni las constantes se pueden importar mediante la sentencia use.
  4. Los nombres de espacios de nombres dinámicos (identificadores entre comillas) deberían escaparse con una barra invertida.
  5. Las constantes no definidas aludidas usando cualquier barra invertida terminan en un error fatal
  6. No se pueden sobrescribir las constantes especiales NULL, TRUE, FALSE, ZEND_THREAD_SAFE o ZEND_DEBUG_BUILD

Si no utilizo espacios de nombres, ¿debería preocuparme por algo de esto?

No. Los espacios de nombres no afectan a ningún código existente de ninguna manera, o a ningún código todavía por escribir que no contenga espacios de nombres. Se puede escribir este código si se desea:

Ejemplo #1 Acceder a clases globales fuera de un espacio de nombres

<?php
$a
= new \stdClass;
?>

Esto es funcionalmente equivalente a:

Ejemplo #2 Acceder a clases globales fuera de un espacio de nombres

<?php
$a
= new stdClass;
?>

¿Cómo uso clases internas o globales en un espacio de nombres?

Ejemplo #3 Acceder a clases internas en espacios de nombres

<?php
namespace foo;
$a = new \stdClass;

function
probar(\ArrayObject $ejemploalusiónatipo = null) {}

$a = \DirectoryIterator::CURRENT_AS_FILEINFO;

// extender una clase interna o global
class MiExcepción extends \Exception {}
?>

¿Cómo uso clases, funciones o constantes de espacios de nombres en su propio espacio de nombres?

Ejemplo #4 Acceder a clases, funciones o constantes internas en un espacio de nombres

<?php
namespace foo;

class
MiClase {}

// usar una clase desde el espacio de nombres actual como una declaración de tipo
function probar(MiClase $ejemploalusiónatipo = null) {}
// otra manera de usar una clase desde el espacio de nombres actual una declaración de tipo
function probar(\foo\MiClase $ejemploalusiónatipo = null) {}

// extender una clase desde el espacio de nombres actual
class Extendida extends MiClase {}

// acceder a una función global
$a = \funcglobal();

// acceder a una constante global
$b = \INI_ALL;
?>

¿Cómo se resuelve un nombre como \mi\nombre o \nombre?

Los nombres que comienzan con una \ siempre se resuelven a aquello a lo que se asemejan, así \mi\nombre de hecho es mi\nombre, y \Exception es Exception.

Ejemplo #5 Nombres completamente cualificados

<?php
namespace foo;
$a = new \mi\nombre(); // instancia a la clase "mi\nombre"
echo \strlen('hola'); // llama a la función "strlen"
$a = \INI_ALL; // $a está establecida al valor de la constante "INI_ALL"
?>

¿Cómo se resuelve un nombre como mi\nombre?

Los nombres que contienen una barra invertida pero no comienzan con una barra invertida como mi\nombre pueden resolverse de dos formas diferentes.

Si hay una sentencia de importación que apode a otro nombre como mi, el alias de importación se aplica a mi en mi\nombre.

De lo contrario, al nombre del espacio de nombres actual se le antepone mi\nombre.

Ejemplo #6 Nombres cualificados

<?php
namespace foo;
use
blah\blah as foo;

$a = new mi\nombre(); // instancia a la clase "foo\mi\nombre"
foo\bar::nombre(); // llama a método estático "nombre" de la clase "blah\blah\bar"
mi\bar(); // llama a la función "foo\mi\bar"
$a = mi\BAR; // establece $a al valor de la constante "foo\mi\BAR"
?>

¿Cómo se resuelve un nombre de clase no cualificado como nombre?

Los nombres de clases que no contienen una barra invertida como nombre se pueden resolver de dos formas diferentes.

Si hay una sentencia de importación que apode a otro nombre como nombre, se aplica el alias de importación.

De lo contrario, al nombre del espacio de nombres actual se le antepone nombre.

Ejemplo #7 Nombres de clases no cualificados

<?php
namespace foo;
use
blah\blah as foo;

$a = new nombre(); // instancia a la clase "foo\nombre"
foo::nombre(); // llama al método estático "nombre" de la clase "blah\blah"
?>

¿Cómo se resuelve un nombre de función o de constante no cualifcado como nombre?

Los nombres de funciones o de constantes que no contienen una barra invertida como nombre se pueden resolver de dos formas diferentes.

Primero, al nombre del espacio de nombres actual se le antepone nombre.

Finalmente, si el nombre de la constante o de la función no existe en el espacio de nombres actual, se emplea un nombre de constante o función global, si es que existe.

Ejemplo #8 Nombres de funciones o constantes no cualificados

<?php
namespace foo;
use
blah\blah as foo;

const
FOO = 1;

function
mi() {}
function
foo() {}
function
sort(&$a)
{
\sort($a); // invoca a la función global "sort"
$a = array_flip($a);
return
$a;
}

mi(); // calls "foo\mi"
$a = strlen('hola'); // llama a la función global "strlen" ya que "foo\strlen" no existe
$array = array(1,3,2);
$b = sort($array); // llama a la función "foo\sort"
$c = foo(); // llama a la función "foo\foo" - la importación no se aplica

$a = FOO; // establece $a al valor de la constante "foo\FOO"; la importación no se aplica
$b = INI_ALL; // establece $b al valor de la constante "INI_ALL"
?>

Importar nombres no entra en conflicto con las clases definidas en el mismo fichero.

Están permitidas las siguientes combinaciones de scripts:

fichero1.php

<?php
namespace mis\cosas;
class
MiClase {}
?>

otro.php

<?php
namespace otro;
class
cosa {}
?>

fichero2.php

<?php
namespace mis\cosas;
include
'fichero1.php';
include
'otro.php';

use
otro\cosa as MiClase;
$a = new MiClase; // instancia a la clase "cosa" del espacio de nombres otro
?>

No existe conflicto entre nombres, aunque la clase MiClase exista dentro del espacio de nombres mis\cosas, porque la definición de MiClase está en otro fichero. Sin embargo, el siguiente ejemplo causa un error fatal por el conflicto entre nombres, debido a que MiClase está definida en el mismo fichero que el de la sentencia use.

<?php
namespace mis\cosas;
use
otro\cosa as MiClase;
class
MiClase {} // error fatal: MiClase entra en conflicto con la sentencia de importación
$a = new MiClase;
?>

Los espacios de nombres anidados no están permitidos.

PHP no permite los espacios de nombres anidados

<?php
namespace mis\cosas {
namespace
anidado {
class
foo {}
}
}
?>
Sin embargo, es fácil simular los espacios de nombres anidados de la siguiente manera:
<?php
namespace mis\cosas\anidado {
class
foo {}
}
?>

Antes de PHP 5.6, ni las funciones ni las constantes se pueden importar mediante la sentencia use.

Ants de PHP 5.6, los únicos elementos que se ven afectados por la sentencia use son los espacios de nombres y los nombres de clases. Para abreviar una constante o una función larga, se ha de importar el espacio de nombres que la contiene:

<?php
namespace mío;
use
nombre\en\ultra\largo;

$a = largo\CONSTANT;
largo\func();
?>
A partir de PHP 5.6, está permitido apodar o imortar nombres de funciones y de constantes.

Los nombres de espacios de nombres dinámicos (identificadores entre comillas) deberían escaparse con una barra invertida.

Es muy importante darse cuenta de que, debeido a que la barra invertida se usa como carácter de escape dentro de cadenas, se deberían emplear dos barras inverticas cuando se utilicen dentro de cadenas. De lo contrario, existe el riesgo de obtener consecuencias inesperadas:

Ejemplo #9 Peligros de usar nombres de espacios de nombres dentro de una cadena entre comillas dobles

<?php
$a
= "peligroso\nombre"; // ¡\n es una nueva línea dentro de las cadenas entre comillas dobles!
$obj = new $a;

$a = 'sin\peligro\alguno'; // aquí sin problemas.
$obj = new $a;
?>
Dentro de una cadena entre comillas dobles, es más seguro usar la secuencia de escape de la barra invertida, pero aún se recomienda como práctica escapar las barras invertidas en todas las cadenas.

Las constantes no definidas a las que se hace referencia usando una barra invertida terminan con un error fatal

Cualquier constante no definida que no sea cualificada, como FOO, generará una aviso explicando que PHP asume que FOO es el valor de la constante. Cualquier constante, cualificada o completamente cualificada, que contenga una barra invertida producirá un error fatal si no se encuentra.

Ejemplo #10 Constantes no definidas

<?php
namespace bar;
$a = FOO; // produce un aviso - constante no definida "FOO" se asume que es "FOO";
$a = \FOO; // error fatal, constante FOO del espacio de nombres no definida
$a = Bar\FOO; // error fatal, constante bar\Bar\FOO del espacio de nombres no definida
$a = \Bar\FOO; // error fatal, constante Bar\FOO del espacio de nombres no definida
?>

No se pueden sobrescribir las constantes especiales NULL, TRUE, FALSE, ZEND_THREAD_SAFE o ZEND_DEBUG_BUILD

Cualquier intento de definir una constante de espacio de nombres que sea una constante especial interna, resultará en un error fatal:

Ejemplo #11 Constantes no definidas

<?php
namespace bar;
const
NULL = 0; // error fatal;
const true = 'estúpido'; // también error fatal;
// etc.
?>

add a note

User Contributed Notes 6 notes

up
15
manolachef at gmail dot com
12 years ago
There is a way to define a namespaced constant that is a special, built-in constant, using define function and setting the third parameter case_insensitive to false:

<?php
namespace foo;
define(__NAMESPACE__ . '\NULL', 10); // defines the constant NULL in the current namespace
var_dump(NULL); // will show 10
var_dump(null); // will show NULL
?>

No need to specify the namespace in your call to define(), like it happens usually
<?php
namespace foo;
define(INI_ALL, 'bar'); // produces notice - Constant INI_ALL already defined. But:

define(__NAMESPACE__ . '\INI_ALL', 'bar'); // defines the constant INI_ALL in the current namespace
var_dump(INI_ALL); // will show string(3)"bar". Nothing unespected so far. But:

define('NULL', 10); // defines the constant NULL in the current namespace...
var_dump(NULL); // will show 10
var_dump(null); // will show NULL
?>

If the parameter case_insensitive is set to true
<?php
namespace foo;
define (__NAMESPACE__ . '\NULL', 10, true); // produces notice - Constant null already defined
?>
up
7
shaun at slickdesign dot com dot au
8 years ago
When creating classes or calling static methods from within namespaces using variables, you need to keep in mind that they require the full namespace in order for the appropriate class to be used; you CANNOT use an alias or short name, even if it is called within the same namespace. Neglecting to take this into account can cause your code to use the wrong class, throw a fatal missing class exception, or throw errors or warnings.

In these cases, you can use the magic constant __NAMESPACE__, or specify the full namespace and class name directly. The function class_exists also requires the full namespace and class name, and can be used to ensure that a fatal error won't be thrown due to missing classes.

<?php

namespace Foo;
class
Bar {
public static function
test() {
return
get_called_class();
}
}

namespace
Foo\Foo;
class
Bar extends \Foo\Bar {
}

var_dump( Bar::test() ); // string(11) "Foo\Foo\Bar"

$bar = 'Foo\Bar';
var_dump( $bar::test() ); // string(7) "Foo\Bar"

$bar = __NAMESPACE__ . '\Bar';
var_dump( $bar::test() ); // string(11) "Foo\Foo\Bar"

$bar = 'Bar';
var_dump( $bar::test() ); // FATAL ERROR: Class 'Bar' not found or Incorrect class \Bar used
up
3
teohad at NOSPAM dot gmail dot com
8 years ago
[Editor's note: that behavior is caused by a bug in PHP 7.0, which has been fixed as of PHP 7.0.7.]

Regarding the entry "Import names cannot conflict with classes defined in the same file".
- I found that since PHP 7.0 this is no longer the case.
In PHP 7.0 you can have a class with a name that matches an imported class (or namespace or both at the same time).

<?php
namespace ns1 {
class
ns1 {
public static function
write() {
echo
"ns1\\ns1::write()\n";
}
}
}

namespace
ns1\ns1 {
class
ns1c {
public static function
write() {
echo
"ns1\\ns1\\ns1c::write()\n";
}
}
}

namespace
ns2 {
use
ns1\ns1 as ns1; // both a class in ns1, and a namespace ns1\ns1

// the next class causes fatal error in php 5.6, not in 7.0
class ns1 {
public static function
write() {
echo
"ns2\\ns1::write()\n";
}
}

ns1::write(); // calls imported ns1\ns1::write()
ns1\ns1c::write(); // calls imported ns1\ns1\ns1c::write()
namespace\ns1::write(); // calls ns2\ns1::write()
}
?>
up
6
phpcoder
9 years ago
Regarding "Neither functions nor constants can be imported via the use statement." Actually you can do it in PHP 5.6+:

<?php

// importing a function (PHP 5.6+)
use function My\Full\functionName;

// aliasing a function (PHP 5.6+)
use function My\Full\functionName as func;

// importing a constant (PHP 5.6+)
use const My\Full\CONSTANT;
?>
up
1
theking2 at king dot ma
2 years ago
Just like class names currently namespaces are not case sensitive. So no errors will be shown here:

<?php declare(strict_types=1);
namespace
Foo;
class
Bar {
public function
__construct() {
echo
'Map constructed';
}
}

$foobar = new \foo\bar();
up
-4
okaresz
11 years ago
To correct manolachef's answer: define() ALWAYS defines constants in the GLOBAL namespace.

As nl-x at bita dot nl states in the note at http://www.php.net/manual/en/function.define.php, the constant "NULL" can be defined with define() case-sensitively, but can only be retrieved with constant(), leaving the meaning of NULL uppercase keyword as the only value of the type null.
To Top