Un namespace de PHP pone clases, funciones y constantes bajo un prefijo para que sus nombres no choquen con los de otros. Lo declaras con namespace App\Models; como primera sentencia de un archivo, y los demás archivos se refieren a la clase como \App\Models\User, o la importan con use App\Models\User; y escriben solo User.
Dentro del namespace, User significa App\Models\User. User::class da el nombre completo como cadena sin crear nada, algo útil para los logs y para los autoloaders.
Dos namespaces en un archivo
Un proyecto real pone un namespace en cada archivo. Para una demo autocontenida, un archivo puede tener varios namespaces si cada uno va entre llaves. El código que no pertenece a ningún namespace va en namespace { }:
Dos clases llamadas Order conviven porque sus nombres completos son distintos. Es justo el problema que resuelven los namespaces en cuanto instalas librerías: tu Order, el Order de una librería de pagos y el Order de una librería de PDF ya no chocan.
Importar con use y crear alias con as
Escribir \Shop\Order en todas partes es ruidoso. use al principio de un archivo (o de un bloque de namespace) importa un nombre para que puedas usar la forma corta. Cuando dos importaciones acabarían en el mismo nombre corto, as le da a una de ellas otro nombre:
use solo crea un nombre corto para el resto del archivo. No carga ningún archivo ni ejecuta código, y funciona igual exista ya la clase o no. También se permiten las importaciones agrupadas: use Shop\{Order, Invoice};.
use function y use const
Las funciones y las constantes de un namespace se importan con use function y use const:
Las clases globales necesitan una barra invertida
Dentro de un namespace, un nombre de clase sin cualificar se resuelve en relación con ese namespace, así que new DateTime() dentro de namespace App; busca App\DateTime. Las funciones y las constantes son distintas: si App\strlen no existe, PHP recurre al strlen global. Las clases nunca recurren al global.
El catch (\Error $e) necesitaba una barra invertida por el mismo motivo: sin ella PHP buscaría App\Error, nunca coincidiría con el error real y el script se detendría con un Error no capturado. Corrígelo con una barra invertida inicial, como arriba, o con use DateTime; al principio del archivo. Lo mismo se aplica a \Exception, \Throwable y cualquier otra clase nativa; consulta try catch para capturarlas.
Autoloading y PSR-4
En un proyecto, cada clase vive en su propio archivo, y la ruta del archivo sigue al namespace. PSR-4 es la convención: un prefijo de namespace se asigna a una carpeta base, y el resto del nombre se convierte en la ruta. Un autoloader registrado con spl_autoload_register() carga entonces el archivo de una clase la primera vez que se usa la clase. Este bloque escribe dos archivos de clase en disco y los carga con autoload:
Cada archivo de clase se carga una vez, en el momento en que la clase se necesita por primera vez. En los proyectos reales no escribes tú esta función: Composer la genera a partir de unas pocas líneas en composer.json:
{
"autoload": {
"psr-4": {
"App\\": "src/"
}
}
}
Después de composer dump-autoload, un único require __DIR__ . '/vendor/autoload.php'; al principio de tu script de entrada carga bajo demanda todas las clases App\....
Reglas de los namespaces que provocan errores
namespacedebe ser la primera sentencia del archivo. Solo pueden ir antesdeclare(strict_types=1);y los comentarios.- Las importaciones con
useson por archivo. Importar una clase enindex.phpno hace que el nombre corto funcione dentro de un archivo incluido; cada archivo necesita sus propias líneasuse. useva en el nivel superior del archivo o del bloque de namespace. Dentro del cuerpo de una clase,usesignifica otra cosa: incorpora un trait.- Las cadenas nunca se resuelven:
$class = 'User'; new $class();busca elUserglobal. Guarda el nombre completo, idealmente conUser::class.
La última merece una comprobación rápida:
Preguntas frecuentes
¿Qué es un namespace en PHP?
Un prefijo que agrupa clases, interfaces, funciones y constantes relacionadas, como una carpeta para nombres. namespace App\Models; al principio de un archivo pone su clase User en App\Models\User, así que no puede chocar con el User de otra librería.
¿Qué hace use en PHP?
use App\Models\User; al principio de un archivo te permite escribir User en lugar del nombre completo \App\Models\User en ese archivo. No carga ni incluye nada; cargar el archivo de la clase es trabajo del autoloader. use ... as Alias; elige otro nombre corto.
¿Por qué obtengo Class not found dentro de un namespace?
Dentro de namespace App; un nombre de clase simple se resuelve de forma relativa al namespace, así que new DateTime() busca App\DateTime. Escribe new \DateTime() o añade use DateTime; al principio. Las funciones y las constantes recurren automáticamente al namespace global; las clases, no.
¿Qué es la barra invertida antes de un nombre de clase en PHP?
Una barra invertida inicial hace que el nombre sea completamente cualificado, empezando por el namespace global: \Exception es siempre la Exception nativa de PHP, esté el código en el namespace que esté. Sin ella, el nombre se resuelve en relación con el namespace actual y las importaciones de use.
¿Qué relación tienen los namespaces con las carpetas y PSR-4?
PHP por sí solo no vincula los namespaces a carpetas. PSR-4 es la convención que lo hace: un prefijo como App\ se asigna a un directorio como src/, así que App\Models\User está en src/Models/User.php. El autoloader de Composer la sigue, y por eso los dos suelen coincidir.