W3docs

Comprendiendo los Namespaces de PHP

Los namespaces de PHP agrupan clases, funciones y constantes en una estructura lógica para evitar conflictos de nombres en proyectos grandes.

Un namespace es una forma de agrupar clases, interfaces, funciones y constantes relacionadas bajo un único nombre lógico. Piénsalo como carpetas en tu disco: dos archivos llamados index.php pueden coexistir siempre que estén en carpetas diferentes. De la misma manera, dos clases llamadas User pueden coexistir siempre que vivan en namespaces distintos.

Sin namespaces, todos los nombres viven en un único espacio global compartido. En el momento en que tu proyecto y una biblioteca de terceros definen una clase llamada Logger o Router, PHP lanza un error fatal Cannot declare class. Los namespaces son la solución estándar a ese problema y son la base del autoloading de Composer (el estándar PSR-4) utilizado por prácticamente todos los paquetes PHP modernos.

Por qué importan los Namespaces

  • Evitar colisiones de nombres. Dos fragmentos de código pueden usar el mismo nombre de clase o función siempre que estén en namespaces diferentes, por lo que tu código nunca choca con el de una biblioteca.
  • Organizar bases de código grandes. Los namespaces reflejan tu estructura de carpetas, dejando claro dónde vive una clase (App\Service\Mailer está en app/Service/Mailer.php).
  • Habilitar el autoloading. PSR-4 mapea un prefijo de namespace a un directorio, de modo que Composer puede cargar clases bajo demanda sin necesidad de sentencias require manuales.

Definiendo un Namespace

Declara un namespace con la palabra clave namespace. Debe ser la primera sentencia del archivo (solo puede ir antes una línea declare(strict_types=1)). Los nombres de namespace usan una barra invertida (\) para separar niveles:

<?php
namespace App\Service;

class Mailer
{
    public function send(string $to): string
    {
        return "Mail sent to {$to}";
    }
}

Todo lo declarado debajo de la línea namespace — la clase Mailer — ahora vive en App\Service. Su nombre completamente calificado es App\Service\Mailer.

Referenciando Elementos con Namespace

Hay tres formas de referirse a un nombre desde otro namespace.

Un nombre completamente calificado comienza con un \ inicial y nombra el elemento desde la raíz global — es inequívoco en cualquier lugar:

<?php
$mailer = new \App\Service\Mailer();

Un nombre calificado es relativo al namespace actual, por lo que Service\Mailer dentro del namespace App se resuelve como App\Service\Mailer. Un nombre sin ninguna barra invertida es no calificado y se busca primero en el namespace actual.

Importando con use

Escribir la ruta completa cada vez es tedioso. La palabra clave use importa un nombre en el archivo actual para que puedas referenciarlo por su nombre corto:

<?php
use App\Service\Mailer;

$mailer = new Mailer();   // resolves to App\Service\Mailer

Alias con as

Cuando dos clases importadas comparten un nombre corto, dale un alias a una con as para desambiguar:

<?php
use App\Service\Mailer;
use Vendor\Mail\Mailer as VendorMailer;

$a = new Mailer();        // App\Service\Mailer
$b = new VendorMailer();  // Vendor\Mail\Mailer

Importando Funciones y Constantes

use importa clases por defecto. Para importar una función o una constante, añade la palabra clave function o const:

<?php
use function App\Helpers\format_price;
use const App\Config\TAX_RATE;

Atención: Las Funciones Incorporadas Necesitan una Barra Invertida Inicial

Dentro de un namespace, un nombre de función o clase no calificado se resuelve contra el namespace actual primero. Para las funciones incorporadas PHP recurre automáticamente a la versión global, pero para las clases incorporadas no lo hace. Por lo tanto, referenciar clases del núcleo como Exception, DateTime o PDO requiere una barra invertida inicial (o una sentencia use):

<?php
namespace App\Service;

// Wrong: PHP looks for App\Service\Exception, which doesn't exist.
// throw new Exception('boom');

// Right: leading backslash points to the global class.
throw new \Exception('boom');

Un patrón habitual y legible es importar la clase del núcleo en la parte superior del archivo:

<?php
namespace App\Service;

use Exception;

throw new Exception('boom');   // now the short name works

Un Ejemplo Completo

Este script autónomo y ejecutable define dos namespaces y usa ambos — mostrando cómo el mismo nombre corto de clase puede vivir en dos lugares sin conflicto:

<?php
namespace App\Billing {
    class Invoice
    {
        public function label(): string
        {
            return 'Billing invoice';
        }
    }
}

namespace App\Shipping {
    class Invoice
    {
        public function label(): string
        {
            return 'Shipping invoice';
        }
    }
}

namespace Main {
    use App\Billing\Invoice;
    use App\Shipping\Invoice as ShippingInvoice;

    $billing  = new Invoice();
    $shipping = new ShippingInvoice();

    echo $billing->label() . "\n";
    echo $shipping->label() . "\n";
}

Salida:

Billing invoice
Shipping invoice

La sintaxis con llaves namespace Foo { ... } solo se usa para poner múltiples namespaces en un archivo (útil para un ejemplo autocontenido). En proyectos reales se pone un namespace por archivo y se confía en el autoloading de Composer.

Namespaces y Autoloading (PSR-4)

En la práctica raramente escribes los límites del namespace a mano para cada archivo — Composer hace el trabajo. Un mapeo PSR-4 en composer.json vincula un prefijo de namespace a una carpeta:

{
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    }
}

Con esto en su lugar, la clase App\Service\Mailer se carga automáticamente desde src/Service/Mailer.php la primera vez que la referencias — sin necesidad de include o require manuales.

Resumen

  • Un namespace agrupa clases, interfaces, funciones y constantes para evitar colisiones de nombres y organizar el código.
  • Se declara con namespace App\Service; como primera sentencia en el archivo.
  • Referencia los elementos por su nombre completamente calificado (\App\Service\Mailer) o, más habitualmente, impórtalos con use y utiliza el nombre corto.
  • Crea alias para nombres que colisionan con as, y recuerda prefijar las clases globales como \Exception con una barra invertida dentro de un namespace.
  • El autoloading PSR-4 mapea un prefijo de namespace a un directorio, que es la forma en que se carga cada paquete de Composer.

Práctica

Práctica
¿Cuáles son los propósitos de los namespaces de PHP?
¿Cuáles son los propósitos de los namespaces de PHP?
Was this page helpful?