Un namespace PHP mette classi, funzioni e costanti sotto un prefisso così i loro nomi non possono entrare in conflitto con quelli di qualcun altro. Lo dichiari con namespace App\Models; come prima istruzione di un file, e gli altri file si riferiscono alla classe come \App\Models\User, oppure la importano con use App\Models\User; e scrivono solo User.
Dentro il namespace, User significa App\Models\User. User::class dà il nome completo come stringa senza creare nulla, comodo per il logging e per gli autoloader.
Due namespace in un file
Un progetto reale mette un namespace in ogni file. Per una demo autonoma, un file può contenerne diversi quando ciascuno è racchiuso tra graffe. Il codice che non appartiene a nessun namespace va in namespace { }:
Due classi chiamate Order vivono fianco a fianco perché i loro nomi completi sono diversi. È esattamente il problema che i namespace risolvono quando installi librerie: il tuo Order, l'Order di una libreria di pagamenti e l'Order di una libreria PDF non si scontrano più.
Importare con use e creare alias con as
Scrivere \Shop\Order ovunque è pesante. use in cima a un file (o a un blocco namespace) importa un nome così puoi usare la forma breve. Quando due import finirebbero con lo stesso nome breve, as dà a uno dei due un nome diverso:
use crea solo un nome breve per il resto del file. Non carica un file né esegue codice, e funziona allo stesso modo che la classe esista già o no. Sono consentiti anche gli import raggruppati: use Shop\{Order, Invoice};.
use function e use const
Le funzioni e le costanti di un namespace si importano con use function e use const:
Le classi globali richiedono una barra rovesciata
Dentro un namespace, un nome di classe non qualificato viene risolto rispetto a quel namespace, quindi new DateTime() dentro namespace App; cerca App\DateTime. Funzioni e costanti sono diverse: se App\strlen non esiste, PHP ripiega sullo strlen globale. Le classi non ripiegano mai.
Anche catch (\Error $e) richiedeva una barra rovesciata per lo stesso motivo: senza, PHP cercherebbe App\Error, non corrisponderebbe mai al vero errore, e lo script si fermerebbe con un Error non catturato. Risolvi con una barra rovesciata iniziale, come sopra, oppure con use DateTime; in cima al file. Lo stesso vale per \Exception, \Throwable e ogni altra classe predefinita; vedi try catch per catturarle.
Autoloading e PSR-4
In un progetto, ogni classe vive nel proprio file, e il percorso del file segue il namespace. PSR-4 è la convenzione: un prefisso di namespace corrisponde a una cartella di base, e il resto del nome diventa il percorso. Un autoloader registrato con spl_autoload_register() carica poi il file di una classe la prima volta che la classe viene usata. Questo blocco scrive su disco due file di classe e li carica automaticamente:
Ogni file di classe viene caricato una volta, nel momento in cui la classe serve per la prima volta. Nei progetti reali non scrivi tu questa funzione: Composer la genera da poche righe in composer.json:
{
"autoload": {
"psr-4": {
"App\\": "src/"
}
}
}
Dopo composer dump-autoload, un solo require __DIR__ . '/vendor/autoload.php'; all'inizio dello script di ingresso carica su richiesta ogni classe App\....
Regole dei namespace che causano errori
namespacedeve essere la prima istruzione del file. Possono precederlo solodeclare(strict_types=1);e i commenti.- Gli import con
usevalgono per file. Importare una classe inindex.phpnon fa funzionare il nome breve dentro un file incluso; ogni file ha bisogno delle proprie righeuse. useva al livello principale del file o del blocco namespace. Dentro il corpo di una classe,usesignifica un'altra cosa: include un trait.- Le stringhe non vengono mai risolte:
$class = 'User'; new $class();cerca loUserglobale. Salva il nome completo, meglio se conUser::class.
L'ultima merita una verifica veloce:
Domande frequenti
Cos'è un namespace in PHP?
Un prefisso che raggruppa classi, interfacce, funzioni e costanti correlate, come una cartella per i nomi. namespace App\Models; in cima a un file mette la sua classe User in App\Models\User, così non può entrare in conflitto con lo User di un'altra libreria.
Cosa fa use in PHP?
use App\Models\User; in cima a un file ti permette di scrivere User invece del nome completo \App\Models\User in quel file. Non carica né include nulla; caricare il file della classe è compito dell'autoloader. use ... as Alias; sceglie un nome breve diverso.
Perché ottengo Class not found dentro un namespace?
Dentro namespace App; un nome di classe semplice viene risolto rispetto al namespace, quindi new DateTime() cerca App\DateTime. Scrivi new \DateTime() oppure aggiungi use DateTime; in cima. Funzioni e costanti ripiegano automaticamente sul namespace globale, le classi no.
Cos'è la barra rovesciata prima di un nome di classe in PHP?
Una barra rovesciata iniziale rende il nome completamente qualificato, a partire dal namespace globale: \Exception è sempre l'Exception predefinita di PHP, in qualunque namespace si trovi il codice. Senza, il nome viene risolto rispetto al namespace corrente e agli import con use.
Che rapporto c'è tra namespace, cartelle e PSR-4?
PHP di per sé non lega i namespace alle cartelle. È PSR-4 la convenzione che lo fa: un prefisso come App\ corrisponde a una cartella come src/, quindi App\Models\User si trova in src/Models/User.php. L'autoloader di Composer la segue, ed è per questo che di solito i due coincidono.