Introdotti con la versione 5.3 di PHP, i namespaces (letteralmente “spazi dei nomi") sono in pratica delle porzioni di memoria che ospitano nomi di elementi definiti in sede di sviluppo e impediscono che eventuali omonimie (Name collisions) possano dar luogo a malfunzionamenti o ambiguità.
Uno dei vantaggi dei namespaces sta nel fatto di poter creare uno spazio indipendente per nomi associati a classi, funzioni e altri elementi che potranno essere richiamati facendo riferimento al namespace di appartenenza.
Per un approfondimento teorico sui namespace si consiglia la lettura di un articolo pubblicato qualche tempo fa su questo stesso sito, in questa sede verrà invece proposto un esempio pratico basilare del loro utilizzo.
Associare funzioni e classi ad un namespace
Nonostante l’introduzione dei namespace sia stata una delle novità più rilevanti e richieste di PHP 5.3, non è facile trovare in rete degli esempi pratici relativi al loro utilizzo; un semplice esempio allo scopo di colmare questa lacuna dovrebbe naturalmente partire dalla definizione di un namespace all’interno di un file che, per rapidità di esposizione, sarebbe possibile denominare semplicemente prova.php; il codice necessario per la definizione sarà il seguente:
<?php
// definizione di un namespace
namespace prova;
?>
Come è possibile notare, un namespace viene introdotto attraverso l’omonima parola chiave; ora che il primo passaggio è stato concluso, “esiste" un namespace denominato “prova" e tutti i costrutti associati (classi, funzioni, costanti etc.) apparterranno ad esso ed esisteranno nell’ambito del suo contesto.
Prima di proseguire, è utile ricordare che quella relativa alla definizione del namespace deve essere tassativamente la prima istruzione presente all’interno del codice che la contiene, per fare un esempio, una sintassi del genere:
echo "Definisco un namespace.";
// definizione di un namespace
namespace prova;
Darà luogo ad una notifica di errore come la seguente:
“Fatal error: Namespace declaration statement has to be the very first statement in the script in .."
Nello stesso modo non potrà essere presente prima di essa alcun output HTML.
Il passaggio successivo sarà quello relativo alla definizione di una funzione appartenente al namespace, per sottolineare l’azione svolta da quest’ultimo contro la “collisione dei nomi", tale funzione prenderà il nome di un’altra già disponibile tramite PHP che, nello specifico, sarà get_loaded_extensions()
, nativamente disponibile per la generazione di un array avente come valori i nomi dei moduli compilati e caricati dal motore del linguaggio; nel caso dell’esempio proposto lo scopo della funzione sarà invece differente:
<?php
// definizione di un namespace
namespace prova;
// dichiarazione di una funzione
function get_loaded_extensions()
{
echo “La dichiarazione della funzione non genera errori.";
}
?>
Da un’operazione del genere ci si aspetterebbe di ricevere in output la notifica di un errore sul modello della seguente:
“Fatal error: Cannot redeclare get_loaded_extensions() in .."
la funzione get_loaded_extensions()
infatti esiste già e dunque non dovrebbe poter essere dichiarata una seconda volta, tale comportamento atteso viene però reso inattivo dalla presenza del namespace all’interno del codice che rimuoverà il conflitto dovuto all’omonimia.
Ritornando su quanto detto in precedenza, è necessario tenere sempre presente che la funzione get_loaded_extensions()
è stata scelta arbitrariamente e la si potrebbe sostituire con un’altra già esistente selezionata casualmente, l’idea di fondo è infatti quella di gestire un qualsiasi conflitto tra nomi, utilizzandone uno che non sarebbe disponibile se al di fuori di un namespace, per uno scopo completamente diverso da quello della funzione a cui è associato.
Per sottolineare quanto affermato, il prossimo passaggio sarà quello di associare alla funzione definita dall’utente un’istruzione che preveda l’esecuzione di una funzione nativa:
function get_loaded_extensions() {
phpinfo();
}
In questo caso phpinfo()
assolverà esattamente il compito per la quale è stata concepita, cioè visualizzare le informazioni relative all’ambiente PHP di riferimento; si noti la presenza del backslash davanti alla funzione, esso ha un ruolo importante nel contesto del namespace, questo perché i nomi dei namespace sono gerarchici e rispettano una disposizione simile a quella dei file all’interno di un File System, così, come esistono directory e sub-directory, esistono infatti anche namespace e sub-namespace, ed è grazie a questa struttura che PHP è in grado di rilevare quale elemento di un namespace viene richiesto all’interno di un’applicazione e dove esso si trova.
In pratica l’identificazione dei namespace funziona sulla base di tre riferimenti:
- Fully-qualified name: è un concetto assimilabile a quello di un percorso assoluto, ad esempio “abc" potrà fare riferimento ad una classe “c" appartenente al namespace “ab", da notare che questa tipologia si caratterizza per il backslash iniziale;
- Qualified name: è un concetto assimilabile a quello di percorso relativo, per cui per esempio “cnome_funzione()" nel contesto del namespace “ab"farà riferimento a “abcnome_funzione()";
- Unqualified name: funziona come il precedente ma fa riferimento soltanto al namespace corrente e non ad eventuali sub-namespaces, per cui “nome_funzione()" in un namespace “abc" sarà risolto tramite “cnome_funzione()".