devdev / in the loop
PHP PHP

Guida PHP 7 guru
I namespace

Una delle feature moderne di PHP che personalmente ritengo una delle più importanti, è quella dei namespace. Sono stati introdotti nella versione 5.3.0 e sono uno strumento indispensabile per fare un po’ di ordine nel nostro codice, creando una gerarchia virtuale dei file, simile a quella che utilizziamo quando usiamo le cartelle del nostro computer. Ogni componente esterno che, ad esempio, utilizziamo (come quelli di Composer) o qualsivoglia framework moderno è fortemente organizzato e vive in un certo namespace in modo da non avere conflitti con gli altri.

Un namespace, quindi, è una semplice gerarchia, fatta di nomi (non necessariamente di file, anche se potrebbe aiutarvi ciò) che ci dice dove trovare e come usare certe classi. Siccome è più facile a farsi che a dirsi, vediamo subito un esempio.

Partiamo da un package reale, utilizziamo il componente HttpFoundation del celebre framework Symfony, che ci servirà per gestire in modo semplice richieste e risposte HTTP all’interno del nostro progetto. Questo componente utilizza nomi delle classi che sono piuttosto semplici, che quindi potrebbero andare in conflitto con altre classi con lo stesso nome, sia che esse facciano parte del nostro codice. sia che vengano da altri componenti esterni. Noi sappiamo, però, che Symfony utilizza appunto il namespace symfony/httpfoundation  e tutte le sue classi vivono sotto di esso.

Come facciamo allora, per esempio, ad utilizzare la classe Response che sta nel componente HttpFoundation?

Partiamo innanzitutto dal come gli sviluppatori hanno creato il namespace, guardando il file dove la classe Response è stata dichiarata. Qui il file in questione, analizziamolo:

<?php

namespace Symfony\Component\HttpFoundation;

Nella prima riga utile, tramite la parola namespace, gli sviluppatori hanno scelto di mettere la classe sotto un percorso, che possiamo paragonare a quello di una directory, oppure di un URL. Come possiamo notare, la prima “directory” è proprio Symfony: questo ci dice immediatamente che il creatore di tale classe è appunto Symfony, questo è il cosiddetto vendor. Sotto di essa c’è la seconda, Component e al di sotto ancora, HttpFoundation. Ricordiamoci che i namespace servono per organizzare il codice: il namespace appena visto è una directory puramente virtuale: non esistono necessariamente cartelle con questo percorso!

Non vi sembra un grande modo per organizzare il codice? Con questa tecnica ogni classe vive in un proprio spazio dove è possibile evitare le collisioni di nome tra il nostro codice e quello dei componenti esterni che utilizziamo.

Creiamo un namespace

Prima di cominciare, diciamo subito che la creazione di namespace è libera nel senso della quantità, cioè non abbiamo limite al numero di namespace dichiarabili, e anche della struttura: essendo delle semplici notazioni testuali, possiamo creare quanti sottolivelli vogliamo. L’importante, per semplicità di utilizzo, è creare namespace con nomi coerenti: per questo motivo il namespace principale (che. come vi anticipavo, in gergo è detto vendor) deve avere un nome che identifica il nostro brand, lo sviluppatore o l’ambiente. Esso è fondamentale ed è consigliabile dichiarare un vendor che sia unico a livello globale. Per questo sito, ipotizziamo, utilizzeremo qualcosa del genere:

<?php

namespace Devdev;

Potremmo pensare poi di creare una gerarchia più completa per scrivere delle classi relative alle guide di questo sito. Le dichiareremo sotto un namespace del tipo Devdev\Guide:

<?php

namespace Devdev\Guide;

class Prova {
    // ...
}

Tutto le classi, funzioni, interfacce che dichiareremo subito sotto, come la classe Prova, vivranno quindi nel namespace Devdev\Guide. Ricordiamoci, inoltre, che non siamo limitati ad un solo file. Possiamo infatti dichiarare questo stesso namespace su più file, scrivendo classi diverse che stanno però sotto lo stesso namespace in file separati.

Utilizzare un namespace

Tornando all’esempio della classe Response che sta sotto il namespace Symfony\Component\HttpFoundation , possiamo dire che il “percorso assoluto della classe” sarebbe appunto Symfony\Component\HttpFoundation\Response . Per non dover scrivere ogni volta il percorso, vediamo come “usare” i namespace. In modo simile a quanto fatto prima, utilizziamo la keywork use seguita dal namespace:

<?php

use Symfony\Component\HttpFoundation;

$prova = new Response();

Stiamo dicendo a PHP di cercare la classe Response nel namespace Symfony\Component\HttpFoundation . Questo sarebbe uguale a scrivere questo:

<?php

$prova = new \Symfony\Component\HttpFoundation\Response();

Come avrete notato, il namespace inizia con un backslash \ . Che significa?

Semplicemente diciamo a PHP che bisogna cercare nello “spazio globale”, cioè a partire dalla radice. Questo equivale al “normale codice PHP” usato senza utilizzare alcun namespace.

<?php

use A\B;

$prova = new Classe(); //Equivale a A\B\Classe();

$prova2 = new \Classe(); //Equivale a Classe(); "globale"

Ci capiterà spesso, nei nostri progetti, di utilizzare più namespace nello stesso momento. Immaginiamo di utilizzare il componente HttpFoundation di Symfony ma anche il componente PHPMailer nello stesso codice. Per utilizzare più di un namespace, utilizziamo semplicemente la keyword use più volte:

<?php

use Symfony\Component\HttpFoundation;
use PHPMailer\PHPMailer;

$prova = new Parse();

PHP cercherà la classe Parse()  rispettivamente prima nel namespace Symfony\Component\HttpFoundation  e poi in in PHPMailer\PHPMailer e poi nello “spazio globale”.

Più namespace nello stesso file

Come abbiamo detto in precedenza, la dichiarazione dei namespace è libera nella quantità e nella forma; possiamo dichiarare lo stesso namespace in più file, ci penserà PHP ad accorparli. Lo stesso vale per il discorso opposto: dichiarare namespace diversi nello stesso file. Anche se vi sconsiglio questa pratica perché può rendere i file disordinati, vediamo come metterla in pratica:

<?php

namespace Devdev {

    function prova() {}

}


namespace Test {

    function prova() {}

}

Come facevamo prima? Semplice, davamo dei nomi assurdi e lunghissimi alle classi o funzioni per scongiurare il pericolo di omonimia. Bei tempi, ma per fortuna andati.

Capitolo successivo → Le interfacce (interface)
Precedente ← Guida PHP 7 guru
if (weekend) {
    relax();
}
la nostra newsletter, ogni tanto.