W3docs

Capire i Namespace PHP

I namespace PHP raggruppano classi, funzioni e costanti in una struttura logica per evitare conflitti di nomi nei progetti.

Un namespace è un modo per raggruppare classi, interfacce, funzioni e costanti correlate sotto un unico nome logico. Immagina le cartelle sul disco: due file chiamati index.php possono coesistere purché si trovino in cartelle diverse. Allo stesso modo, due classi chiamate User possono coesistere purché si trovino in namespace diversi.

Senza i namespace, ogni nome vive in un unico spazio globale condiviso. Nel momento in cui il tuo progetto e una libreria di terze parti definiscono entrambi una classe chiamata Logger o Router, PHP genera un errore fatale Cannot declare class. I namespace sono la soluzione standard a questo problema e sono la base dell'autoloading di Composer (lo standard PSR-4) utilizzato da praticamente ogni pacchetto PHP moderno.

Perché i Namespace Sono Importanti

  • Evitare collisioni di nomi. Due porzioni di codice possono usare lo stesso nome di classe o funzione purché si trovino in namespace diversi, quindi il tuo codice non entra mai in conflitto con quello di una libreria.
  • Organizzare grandi codebase. I namespace rispecchiano la struttura delle cartelle, rendendo ovvio dove si trova una classe (App\Service\Mailer si trova in app/Service/Mailer.php).
  • Abilitare l'autoloading. PSR-4 mappa un prefisso di namespace a una directory, quindi Composer può caricare le classi su richiesta senza istruzioni require manuali.

Definire un Namespace

Dichiara un namespace con la parola chiave namespace. Deve essere assolutamente la prima istruzione nel file (solo una riga declare(strict_types=1) può precederla). I nomi dei namespace usano una barra rovesciata (\) per separare i livelli:

<?php
namespace App\Service;

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

Tutto ciò che viene dichiarato sotto la riga namespace — la classe Mailer — vive ora in App\Service. Il suo nome completo è App\Service\Mailer.

Riferirsi a Elementi con Namespace

Esistono tre modi per fare riferimento a un nome da un altro namespace.

Un nome completamente qualificato inizia con una \ iniziale e indica l'elemento dalla radice globale — è privo di ambiguità ovunque:

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

Un nome qualificato è relativo al namespace corrente, quindi Service\Mailer all'interno del namespace App si risolve in App\Service\Mailer. Un nome senza alcuna barra rovesciata è non qualificato e viene cercato prima nel namespace corrente.

Importare con use

Scrivere il percorso completo ogni volta è noioso. La parola chiave use importa un nome nel file corrente in modo da poterlo referenziare con il suo nome breve:

<?php
use App\Service\Mailer;

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

Creare Alias con as

Quando due classi importate condividono un nome breve, assegna un alias a una di esse con as per disambiguare:

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

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

Importare Funzioni e Costanti

use importa classi per impostazione predefinita. Per importare una funzione o una costante, aggiungi la parola chiave function o const:

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

Attenzione: Le Funzioni Built-in Richiedono una Barra Rovesciata Iniziale

All'interno di un namespace, un nome di funzione o classe non qualificato viene risolto prima rispetto al namespace corrente. Per le funzioni built-in PHP ricade automaticamente alla versione globale, ma per le classi built-in non lo fa. Quindi fare riferimento a classi core come Exception, DateTime o PDO richiede una barra rovesciata iniziale (o un'istruzione 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 pattern comune e leggibile è importare la classe core nella parte superiore del file:

<?php
namespace App\Service;

use Exception;

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

Un Esempio Completo

Questo script singolo ed eseguibile definisce due namespace e li utilizza entrambi — mostrando come lo stesso nome di classe breve possa esistere in due posti senza conflitti:

<?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";
}

Output:

Billing invoice
Shipping invoice

La sintassi namespace Foo { ... } con parentesi graffe viene usata solo per inserire più namespace in un unico file (utile per un esempio autonomo). Nei progetti reali si mette un namespace per file e si fa affidamento sull'autoloading di Composer.

Namespace e Autoloading (PSR-4)

In pratica non si scrivono mai manualmente i confini dei namespace per ogni file — ci pensa Composer. Un mapping PSR-4 in composer.json collega un prefisso di namespace a una cartella:

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

Con questa configurazione, la classe App\Service\Mailer viene caricata automaticamente da src/Service/Mailer.php la prima volta che la si referenzia — senza necessità di include o require manuali.

  • Un namespace raggruppa classi, interfacce, funzioni e costanti per prevenire collisioni di nomi e organizzare il codice.
  • Dichiaralo con namespace App\Service; come prima istruzione nel file.
  • Fai riferimento agli elementi tramite il loro nome completamente qualificato (\App\Service\Mailer) o, più comunemente, importali con use e usa il nome breve.
  • Crea alias per nomi in conflitto con as, e ricordati di prefissare le classi globali come \Exception con una barra rovesciata all'interno di un namespace.
  • L'autoloading PSR-4 mappa un prefisso di namespace a una directory, che è il modo in cui viene caricato ogni pacchetto Composer.

Pratica

Pratica
Quali sono gli scopi dei namespace PHP?
Quali sono gli scopi dei namespace PHP?
Was this page helpful?