PHP 8.0 è un importante aggiornamento che contiene molte nuove funzionalità e ottimizzazioni volte a rendere questo linguaggio sempre più veloce e affidabile.
Anche se questa versione è ancora in fase di sviluppo, sono già state approvate e implementate molte RFC (Request for Comments), informazioni riguardanti nuove ricerche e innovazioni.
Tra le principali novità troviamo:
- Nuove built-in functions
- Errori di tipo coerenti per le built-in functions
- Constructor Property Promotion
- Union Types 2.0
- Espressione Match
- Operatore Nullsafe
- JIT compilation
Nuove built-in functions
Fino a PHP 7 abbiamo dovuto cercare “l’ago” all’interno di un “pagliaio” di tipo stringa tramite la funzione strpos() ,pur essendo poco intuitiva per tutti i novelli sviluppatori PHP.
Ecco un esempio:
La nuova versione 8 invece ci regala una nuova funzione molto intuitiva che ci permette di cercare direttamente all’interno di una stringa restituendoci true o false e accetta gli stessi parametri della precedente:
Sì, avete letto bene, la built-in function in questione si chiama proprio str_contains() e ci ricorda una funzione helper di un noto framework da noi molto utilizzato, Laravel.
Oltre a str_contains() due nuove funzioni arricchiscono l’arsenale a disposizione degli sviluppatori PHP per verificare se una stringa inizia o finisce con una determinata sottostringa:
Da questo semplicissimo esempio capiamo dunque che queste nuove funzioni sono ottimali e intuitive al punto giusto, volte a facilitare la comprensione e quindi l’utilizzo da parte di un pubblico sempre più ampio ma soprattutto a entrare letteralmente in simbiosi con tutti i framework scritti in PHP.
Errori di tipo coerenti per built-in functions
Un altro aspetto aggiornato è quello dell’errore dato dalla convalida dei parametri. La maggior parte delle built-in functions ora lancia un errore di tipo definito se la convalida dei parametri fallisce, spiegandolo in modo coerente.
PHP 7
PHP 8
Le funzioni custom, ovvero quelle definite dall'utente, lanciano già un TypeError, ma le funzioni interne no, lanciano un warning e restituiscono null.
A partire da PHP 8 il comportamento degli errori delle built-in functions è stato reso coerente, come abbiamo appena visto.
Constructor Property Promotion
Per migliorare l’ergonomia degli oggetti in PHP, è stata proposta una nuova e più semplice sintassi per la dichiarazione delle proprietà. L’aggiornamento riguarda quindi solo i promoted parameters, ovvero tutti quei parametri preceduti dalle visibility keywords: public, protected e private.
Quando un parametro è preceduto da una delle visibility keywords viene considerato "promosso". Per ogni parametro promosso, verrà aggiunta una proprietà con lo stesso nome e un'assegnazione a quella proprietà inclusa nel corpo del costruttore.
Fino a PHP 7 quindi tutte le proprietà dovevano essere ripetute più volte prima di poter essere utilizzate con gli oggetti: nella dichiarazione, come parametri del costruttore e nell’assegnazione:
Con PHP 8 non è più necessario dichiarare una proprietà, definirla come parametro e infine assegnarla, ma basta definirla direttamente come parametro del costruttore preceduta dalla visibility keyword scelta, fin troppo semplice:
Come possiamo vedere otteniamo lo stesso identico output, riducendo notevolmente la quantità di boilerplate code, ovvero una sezione di codice ripetuta più e più volte all’interno del nostro programma, come spiega il creatore di questa RFC Nikita Popov:
“È una semplice trasformazione sintattica quella che stiamo facendo. Ma ciò riduce la quantità di codice boilerplate che devi scrivere in particolare per oggetti valorizzati, perché per quelli comunemente non hai davvero bisogno di molto di più delle tue proprietà e del costruttore.”
È chiaro quindi che nel caso utilizzassimo oggetti valorizzati, andremmo a ridurre ancora di più la quantità di sezioni di codice riscritte.
N.B.: PHP 8 introduce adesso le virgole finali nelle liste dei paramentri di funzioni, metodi e closure (vedi esempio precedente).
Le proprietà promosse, inoltre, possono essere utilizzate senza limiti anche nell’ereditarietà con la stessa identica sintassi:
N.B.: Le proprietà promosse non sono ammesse nelle classi astratte e nei trait.
Consiglio tuttavia, ai fini dell’insegnamento, di utilizzare prima il vecchio metodo secondo il quale una proprietà dovesse essere prima dichiarata, poi definita come parametro e infine assegnata nel corpo del costruttore, in modo tale da far capire ad un nuovo sviluppatore PHP come effettivamente avviene la costruzione di un oggetto.
Union Types 2.0
Gli Union Types accettano valori che possono essere di diversi tipi. PHP 7 non forniva supporto per gli Union Types che potevano essere specificati solo nelle annotazioni, come mostrato nell’esempio:
PHP 8 aggiunge il supporto per gli Union Types permettendoci di definirli all’interno della lista dei parametri delle funzioni, con la seguente sintassi:
Il supporto degli Union Types ci permette di spostare informazioni sui tipi dalle annotazioni alle firme delle funzioni, potendo quindi cogliere errori in anticipo avendo applicato dei tipi e riducendo la quantità di codice boilerplate rispetto al vecchio metodo delle annotazioni phpdoc.
Espressione Match
Quando devo racchiudere in un unico blocco di codice diverse istruzioni condizionali scelgo sempre il costrutto switch, molto più leggibile e semplice da gestire rispetto all’elseif:
Se la condizione è soddisfatta dal primo case allora restituiscimi l’istruzione specificata ed esci dal costrutto (break), altrimenti continua la verifica. Se la condizione non è soddisfatta da nessun caso, allora restituiscimi l’istruzione di default. Tutto abbastanza semplice.
PHP 8 propone una nuova espressione di corrispondenza chiamata appunto match, un’espressione dal confronto rigoroso il cui risultato può essere memorizzato in una variabile o restituito.
Vediamo il suo comportamento rispetto allo switch con un esempio:
PHP 7
PHP 8
L‘espressione match quindi lavora senza lo statement break. Esegue solo il ramo corrispondente e restituisce immediatamente il valore, il che implica break subito dopo l'espressione eseguita dal ramo corrispondente.
È tuttavia supportato l’inserimento di un’istruzione di default molto simile a quella del costrutto switch, ma con sintassi differente:
N.B.: i rami match supportano solo espressioni a riga singola e non richiedono un'interruzione; in un'espressione match deve essere presente una condizione che corrisponda all'espressione o un caso di default per gestirla. Se non ci sono corrispondenze, viene generato un errore fatale.
Operatore Nullsafe
Se in passato hai utilizzato l'operatore null, probabilmente hai notato anche i suoi difetti: null non funziona sulle chiamate ai metodi. È necessario effettuare controlli intermedi o affidarsi ad helper opzionali forniti da alcuni framework come Laravel.
PHP 7
Con PHP 8 è ora possibile utilizzare una catena di chiamate con il nuovo operatore nullsafe (?), permettendoci quindi anche dei controlli sulle chiamate ai metodi, vediamo come:
N.B.: quando la valutazione di un elemento della catena fallisce, l'esecuzione dell'intera catena si interrompe e l'intera catena restituisce null.
JIT compilation
PHP 8 introduce due nuovi motori di compilazione JIT (Just-In-Time): Tracing JIT e Function JIT.
Tracing JIT, il più promettente dei due, mostra prestazioni circa 3 volte migliori sui benchmark sintetici e 1,5-2 volte il miglioramento su alcune specifiche applicazioni a lunga esecuzione. Le prestazioni tipiche delle applicazioni sono alla pari con PHP 7.4.
Possiamo quindi definire JIT come una modalità di compilazione durante il funzionamento stesso di un’applicazione, ovvero in runtime.
La proposta della RFC:
“PHP JIT è implementato come parte quasi indipendente di OPcache. Può essere abilitato/disabilitato al momento della compilazione di PHP e al run-time. Quando è abilitato, il codice nativo dei file PHP è memorizzato in una regione aggiuntiva della memoria condivisa di OPcache e gli op_array→opcodes[].handler(s) mantengono i puntatori sugli entry points del codice JIT.”
OPcode? OPcache?
Un OPcode (operation code) è una porzione di un’istruzione in linguaggio macchina che specifica le operazioni da eseguire.
Quindi OPcache, dopo la prima volta che un determinato script è stato eseguito, non fa altro che eliminare le fasi di caricamento/parsing/compilazione avendole già salvate su disco oppure in RAM in precedenza (durante la prima esecuzione).
In breve, con la versione 8 sarà significativamente tutto più veloce, ma per il momento la maggior parte del codice PHP esistente nel mondo manterrà degli standard che risultano ancora approssimativamente lenti. Tuttavia, nuovi sviluppi si apriranno per la nuova versione PHP compilata JIT.
Infine consiglio l’utilizzo di JIT se la vostra applicazione è destinata a svolgere compiti di tipo matematico dove il carico di lavoro è notevole, mentre se l’obiettivo è utilizzare PHP in modo comune, come la maggior parte degli utenti WordPress, le differenze saranno minime (vedi immagine).
In questo articolo ho elencato e descritto le più importanti novità di PHP 8.0 che sicuramente sfrutteremo più spesso, ma gli aggiornamenti minori e le RFC proposte non finiscono qui. Per informazioni extra o approfondimenti vi consiglio e vi consiglierò sempre come prima scelta assoluta il Manuale PHP, presente sul sito ufficiale www.php.net, dal quale potete scaricare l’ultima versione e su cui potete trovare validi e concreti esempi riguardo tutti i metodi descritti in questo articolo.
Antonio Masoni
Junior Backend Developer & Hackademy Tutor
Aulab