PHP 8.1 è finalmente arrivato, e ci porterà altre funzionalità interessanti. Il suo rilascio è previsto per la fine di quest’anno, il 25 novembre 2021.

In questo articolo, analizzeremo in dettaglio le novità di PHP 8.1. Dalle nuove funzionalità ai miglioramenti delle prestazioni, dalle modifiche più significative, fino alle deprecazioni. Analizzeremo tutto in profondità.

Mettetevi comodi!

Nuove Funzionalità in PHP 8.1

Cominciamo ad analizzare tutte le nuove funzionalità di PHP 8.1. È un bell’elenco.

Tipi Intersezione Pura

PHP 8.1 introduce il supporto per i tipi intersezione. È simile ai tipi union introdotti in PHP 8.0, ma il loro utilizzo previsto è l’esatto opposto.

Per capire meglio, rinfreschiamoci la memoria su come funzionano le dichiarazioni dei tipi in PHP.

Essenzialmente, potete aggiungere dichiarazioni di tipo agli argomenti delle funzioni, ai valori di ritorno e alle proprietà delle classi. Questa assegnazione è chiamata type hinting e assicura che il valore sia del tipo corretto al momento della chiamata. In caso contrario, emette subito un TypeError. Questo vi aiuta a fare meglio il debug del codice.

Tuttavia, dichiarare un singolo tipo ha i suoi limiti. Gli Union Type vi aiutano a superare questo problema permettendovi di dichiarare un valore con più tipi, e l’input deve soddisfare almeno uno dei tipi dichiarati.

D’altra parte, la RFC descrive i tipi intersezione come:

Un “intersection type” richiede che un valore soddisfi più vincoli di tipo invece di uno solo.

…gli intersection type puri sono specificati utilizzando la sintassi T1&T2&… e possono essere utilizzati in tutte le posizioni dove i tipi sono accettati al momento…

Notate l’uso dell’operatore & (AND) per dichiarare i tipi intersezione. Al contrario, utilizziamo l’operatore | (OR) per dichiarare i tipi di unione.

Usando la maggior parte dei tipi standard in un tipo di intersezione si otterrà un tipo che non potrà mai essere soddisfatto (ad es. intero e stringa). Quindi, i tipi intersezione possono includere solo tipi di classe (cioè interfacce e nomi di classi).

Ecco un esempio di codice in cui si utilizzano i tipi intersezione:

class A {
    private Traversable&Countable $countableIterator;
 
    public function setIterator(Traversable&Countable $countableIterator): void {
        $this->countableIterator = $countableIterator;
    }
 
    public function getIterator(): Traversable&Countable {
        return $this->countableIterator;
    }
}

Nel codice qui sopra, abbiamo definito una variabile countableIterator come intersezione di due tipi: Traversable e Countable. In questo caso, i due tipi dichiarati sono interfacce.

I tipi intersezione sono anche conformi alle regole di varianza standard di PHP già utilizzate per il controllo dei tipi e l’ereditarietà. Ma ci sono due regole aggiuntive che riguardano il modo in cui i tipi intersezione interagiscono con la sottotipizzazione. Potete approfondire le regole di varianza dei tipi intersezione nella RFC.

In alcuni linguaggi di programmazione, è possibile combinare Tipi Unione e Tipi Intersezione nella stessa dichiarazione. Ma PHP 8.1 lo proibisce. Quindi, la sua implementazione è chiamata tipi intersezione “pura”. Tuttavia, l’RFC afferma che questo è “lasciato come scopo futuro”.

Enums

PHP 8.1 sta finalmente aggiungendo il supporto per gli enum (chiamati anche enumerazioni o tipi enumerati). Sono un tipo di dati definito dall’utente che consiste in un insieme di possibili valori.

L’esempio più comune di enum nei linguaggi di programmazione è il tipo booleano, con true e false come possibili valori. È così comune che è supportato da molti linguaggi di programmazione moderni.

Come da RFC, all’inizio gli enum in PHP saranno limitati a “enumerazioni di unità”:

Lo scopo di questa RFC è limitato alle “enumerazioni di unità”, cioè le enumerazioni che sono esse stesse un valore, piuttosto che semplicemente una sintassi di fantasia per una costante primitiva, e non includono informazioni aggiuntive associate. Questa capacità offre un supporto molto esteso per la modellazione dei dati, definizioni di tipi personalizzati e comportamenti in stile monade. Gli enum permettono la tecnica di modellazione di “rendere irrappresentabili gli stati non validi”, che porta a un codice più solido e minore bisogno di test esaustivi.

Per arrivare a questo stadio, il team PHP ha studiato molti linguaggi che già supportano le enumerazioni. La loro indagine ha rilevato che si possono categorizzare le enumerazioni in tre gruppi generali: Costanti fantasiose, oggetti fantasiosi e tipi di dati algebrici completi (ADT). È una lettura interessante!

PHP implementa gli enum “Fancy Objects”, con l’intenzione di estenderli agli ADT completi in futuro. È concettualmente e semanticamente modellato dopo i tipi enumerati in Swift, Rust e Kotlin, anche se non è direttamente modellato su nessuno di questi.

La RFC usa la famosa analogia dei semi in un mazzo di carte per spiegare come funzionerà:

enum Suit {
  case Hearts;
  case Diamonds;
  case Clubs;
  case Spades;
}

Qui, l’enum Suit definisce quattro possibili valori: Hearts, Diamonds, Clubs e Spades. Potete accedere a questi valori direttamente usando la sintassi: Suit::Hearts, Suit::Diamonds, Suit::Clubs e Suit::Spades.

Questo tipo di utilizzo può sembrare familiare, perché gli enum sono costruiti in cima a classi e oggetti. Si comportano in modo simile e hanno quasi gli stessi requisiti. Gli enum condividono gli stessi spazi dei nomi di classe, interfacce e tratti.

Gli enum menzionati sopra sono chiamati Enum Puri.

Potete anche definire Backed Enum se volete dare un valore scalare equivalente a qualsiasi caso. Tuttavia, i Backed Enum possono avere solo un tipo, o int o string (mai entrambi).

enum Suit: string {
  case Hearts = 'H';
  case Diamonds = 'D';
  case Clubs = 'C';
  case Spades = 'S';
}

Inoltre, tutti i diversi casi di Backed Enum devono avere un valore univoco. E non si possono mai mischiare i due tipo di enum.

L’RFC approfondisce ulteriormente i metodi enum, i metodi statici, le costanti, le espressioni costanti e molto altro. Analizzarli tutti va oltre lo scopo di questo articolo, ma potete fare riferimento alla documentazione.

Il Tipo di Ritorno never

PHP 8.1 aggiunge un nuovo type hint di ritorno chiamato never. È molto utile nelle funzioni si concludono sempre con throw o exit.

Come da RFC, le funzioni di redirect degli URL con exit (esplicitamente o implicitamente) sono un buon esempio del suo utilizzo:

function redirect(string $uri): never {
    header('Location: ' . $uri);
    exit();
}
 
function redirectToLoginPage(): never {
    redirect('/login');
}

Una funzione dichiarata never dovrebbe soddisfare tre condizioni:

  • Non dovrebbe avere la dichiarazione return definita esplicitamente.
  • Non dovrebbe avere la dichiarazione return definita implicitamente (ad esempio, dichiarazioni if-else).
  • Deve terminare la sua esecuzione con una dichiarazione exit (esplicitamente o implicitamente).

L’esempio di redirect di URL qui sopra mostra l’uso sia esplicito che implicito del tipo di ritorno never.

Il tipo di ritorno never ha molte somiglianze con il tipo di ritorno void. Entrambi assicurano che la funzione o il metodo non restituisca un valore. Tuttavia, è diverso perché applica regole più rigide. Ad esempio, una funzione dichiarata void può ancora concludersi con return senza un valore esplicito, ma non potete fare lo stesso con una funzione dichiarata never.

Come regola generale, usate void quando vi aspettate che PHP continui l’esecuzione dopo la chiamata della funzione. Utilizzate never quando volete il contrario.

Inoltre, never è definito come un tipo “bottom”. Quindi, qualsiasi metodo di classe dichiarato never non può “mai” cambiare il suo tipo di return in qualcos’altro. Tuttavia, è possibile estendere un metodo dichiarato void con un metodo dichiarato never.

Fiber

Storicamente, il codice PHP è quasi sempre stato un codice sincrono. L’esecuzione del codice si ferma finché non viene restituito il risultato, anche per le operazioni di I/O. Potete immaginare perché questo processo può rallentare l’esecuzione del codice.

Ci sono molteplici soluzioni di terze parti per superare questo ostacolo e permettere agli sviluppatori di scrivere codice PHP in modo asincrono, specialmente per operazioni di I/O concorrenti. Alcuni esempi sono amphp, ReactPHP e Guzzle.

Tuttavia, non c’è un modo standard per gestire queste istanze in PHP. Inoltre, trattare il codice sincrono e asincrono nello stesso stack di chiamate porta ad altri problemi.

Le Fiber sono il modo di PHP di gestire il parallelismo tramite thread virtuali (o thread verdi). In questo modo si cerca di eliminare la differenza tra codice sincrono e asincrono permettendo alle funzioni PHP di interrompersi senza influenzare l’intero stack delle chiamate.

Ecco cosa promette l’RFC:

  • Aggiunge il supporto delle Fiber in PHP.
  • Introduce una nuova classe Fiber e la corrispondente classe di riflessione ReflectionFiber.
  • Aggiunge classi di eccezione FiberError e FiberExit per rappresentare gli errori.
  • Le Fiber permettono implementazioni trasparenti di I/O delle interfacce esistenti non bloccanti (PSR-7, Doctrine ORM, ecc.). Questo perché l’oggetto segnaposto (promessa) viene eliminato. Le funzioni possono dichiarare il tipo di risultato I/O invece di un oggetto segnaposto che non può specificare un tipo di risoluzione perché PHP non supporta i generici.

Potete utilizzare le Fiber per sviluppare funzioni PHP full-stack, interrompibili, che potete poi utilizzare per implementare il multitasking cooperativo in PHP. Dato che Fibers mette in pausa l’intero stack di esecuzione, potete stare tranquilli sapendo che questo non danneggerà il resto del codice.

Grafico che illustra il flusso di esecuzione del codice PHP con Fiber. (PHP.net)
Grafico che illustra il flusso di esecuzione del codice PHP con Fiber. (PHP.net)

Per illustrare il modo in cui utilizzare le Fiber, l’RFC riporta questo semplice esempio:

$fiber = new Fiber(function (): void {
    $value = Fiber::suspend('fiber');
    echo "Value used to resume fiber: ", $value, "\n";
});
 
$value = $fiber->start();
 
echo "Value from fiber suspending: ", $value, "\n";
 
$fiber->resume('test');

Nel codice di cui sopra create una “fibra” e la sospendete immediatamente con la stringa fiber. La dichiarazione echo serve come spunto visivo per la ripresa della fibra.

Si può recuperare questo valore di stringa dalla chiamata a $fiber-> start().

Poi, si riprende la fibra con la stringa “test”, che viene restituita dalla chiamata a Fiber::suspend(). L’esecuzione completa del codice risulta in questo output:

Value from fiber suspending: fiber
Value used to resume fiber: test

Questo è l’esempio da manuale delle “PHP Fibers” al lavoro. Ecco un altro esempio di Fiber che esegue sette richieste GET asincrone.

Con tutto ciò che è stato detto e fatto, la maggior parte degli sviluppatori PHP non avrà mai a che fare direttamente con le Fiber. E l’RFC suggerisce addirittura la stessa cosa:

Le Fiber sono una funzionalità avanzata che la maggior parte degli utenti non utilizzerà direttamente. Questa funzionalità è rivolta principalmente agli autori di librerie e framework per fornire un ciclo di eventi e un’API di programmazione asincrona. Le Fiber permettono di integrare l’esecuzione di codice asincrono senza interruzioni nel codice sincrono in qualsiasi punto senza la necessità di modificare lo stack delle chiamate dell’applicazione o aggiungere codice boilerplate.

Non ci si aspetta che l’API Fiber sia utilizzata direttamente nel codice a livello di applicazione. Le Fiber forniscono un’API di base e di basso livello per il controllo del flusso per creare astrazioni di livello superiore che sono poi utilizzate nel codice dell’applicazione.

Considerando i vantaggi in termini di prestazioni, ci si può aspettare che le librerie e i framework PHP approfittino di questa nuova funzionalità. Sarà interessante vedere come implementeranno le Fiber nel loro ecosistema.

Nuove Proprietà readonly

PHP 8.1 aggiunge il supporto per le proprietà readonly. Possono essere inizializzate solo una volta dallo scopo in cui sono dichiarate. Una volta inizializzate, non sarà possibile modificare il loro valore. Farlo significherebbe lanciare un’eccezione di Error.

La RFC recita:

Una proprietà readonly può essere inizializzata solo una volta, e solo dallo scopo in cui è stata dichiarata. Qualsiasi altra assegnazione o modifica della proprietà risulterà in un’eccezione Error.

Ecco un esempio d’uso:

class Test {
    public readonly string $kinsta;
 
    public function __construct(string $kinsta) {
        // Legal initialization.
        $this->kinsta = $kinsta;
    }
}

Una volta inizializzato, non si può tornare indietro. Avere questa funzionalità nativamente in PHP riduce notevolmente il codice boilerplate che spesso utilizzato per abilitarla.

La proprietà readonly offre una forte garanzia di immutabilità, sia dentro che fuori la classe. Non importa quale codice venga eseguito nel mezzo. Invocare una proprietà readonly restituirà sempre lo stesso valore.

Tuttavia, utilizzare le proprietà readonly può non essere ideale in casi d’uso specifici. Ad esempio, potete utilizzarle solo insieme a una proprietà tipizzata, perché le dichiarazioni senza un tipo sono implicitamente null e non possono essere readonly.

Inoltre, impostare una proprietà readonly non rende gli oggetti immutabili. La proprietà readonly manterrà lo stesso oggetto, ma l’oggetto stesso può cambiare.

Un altro problema minore con questa proprietà è che non è possibile clonarla. C’è già un workaround per questa particolare situazione. Cercatelo, se necessario.

Definire Costanti di Classe final

A partire da PHP 8.0, è possibile sovrascrivere le costanti di classe con le classi child. Ciò è dovuto al modo in cui l’ereditarietà è implementata in PHP.

Ecco un esempio che illustra come sovrascrivere il valore di una costante dichiarata in precedenza:

class Moo
{
    public const M = "moo";
}
 
class Meow extends Moo
{
    public const M = "meow";
}  

Ora, se le mucche vogliono diventare più severe sul comportamento dei gatti (almeno con le costanti), possono farlo con il nuovo modificatore final di PHP 8.1.

Una volta che avete dichiarato una costante come final, significa proprio questo.

class Moo
{
    final public const M = "moo";
}
 
class Meow extends Moo
{
    public const M = "meow";
}
 
// Fatal error: Meow::M cannot override final constant Moo::M

Potete approfondire l’argomento nella RFC sulle costanti finali di classe in PHP.

Funzioni fsync() e fdatasync()

PHP 8.1 aggiunge due nuove funzioni di file system chiamate fsync() e fdatasync(). Sembreranno familiari a chi conosce le funzioni Linux con lo stesso nome. Questo perché sono correlate, solo implementate per PHP.

In effetti, questa novità era attesa da tempo. PHP è uno dei pochi grandi linguaggi di programmazione che ancora non implementava fsync() e fdatasync() – almeno fino a PHP 8.1.

La funzione fsync() è simile alla funzione esistente fflush() di PHP, ma differisce in un modo significativo per un motivo. Mentre fflush() esegue il flush dei buffer interni dell’applicazione verso il sistema operativo, fsync() fa un passo avanti e fa sì che i buffer interni vengano esguiti sulla memoria fisica. Questo assicura una scrittura completa e persistente che permette di recuperare i dati anche dopo un crash dell’applicazione o del sistema.

Ecco un esempio.

$doc = 'kinsta.txt';

$kin = fopen($doc, 'ki');
fwrite($kin, 'doc info');
fwrite($kin, "\r\n");
fwrite($kin, 'more info');

fsync($kin);
fclose($kin);

Aggiungere la chiamata fsync() alla fine assicura che tutti i dati contenuti nel buffer interno di PHP o del sistema operativo vengano scritti nella memoria. Tutte le altre esecuzioni di codice sono bloccate fino ad allora.

La sua funzione correlata è fdatasync(). Questa va utilizzata per sincronizzare i dati ma non necessariamente i metadati. Per i dati i cui metadati non sono essenziali, questa chiamata di funzione rende la scrittura un po’ più veloce.

Tuttavia, si noti che PHP 8.1 non supporta ancora completamente fdatasync() su Windows. Funge semplicemente da alias di fsync(). Su POSIX, fdatasync() è implementato correttamente.

Nuova Funzione array_is_list()

Gli array PHP possono contenere sia chiavi intere che stringhe. Questo significa che potete utilizzarli per diverse cose, come liste, tabelle hash, dizionari, collezioni, pile, code e molto altro. Potete anche avere array dentro array, creando array multidimensionali.

Si può verificare se una particolare voce è un array, ma non è così facile controllare se questo ha qualche offset di array mancante, chiavi fuori ordine, ecc. In breve, non è possibile verificare rapidamente se un array è una lista.

La funzione array_is_list() controlla se le chiavi di un array sono in ordine sequenziale a partire da 0 e senza spazi vuoti. Se tutte le condizioni sono soddisfatte, restituisce true. Di default, restituisce true anche per gli array vuoti.

Ecco alcuni esempi con condizioni sia true che false:

// true array_is_list() examples
array_is_list([]); // true
array_is_list([1, 2, 3]); // true
array_is_list(['cats', 2, 3]); // true
array_is_list(['cats', 'dogs']); // true
array_is_list([0 => 'cats', 'dogs']); // true
array_is_list([0 => 'cats', 1 => 'dogs']); // true 

// false array_is_list() examples 
array_is_list([1 => 'cats', 'dogs']); // as first key isn't 0
array_is_list([1 => 'cats', 0 => 'dogs']); // keys are out of order
array_is_list([0 => 'cats', 'bark' => 'dogs']); // non-integer keys
array_is_list([0 => 'cats', 2 => 'dogs']); // gap in between keys 

Una lista di array PHP con chiavi fuori ordine è una potenziale fonte di bug. Questa funzione può essere utilizzata per imporre una stretta aderenza ai requisiti della lista prima di andare avanti con l’esecuzione del codice.

Nuove Funzioni Sodium XChaCha20

Sodium è una libreria semplice e moderna per la crittografia, la decrittografia, l’hashing delle password, le firme e altro. Il pacchetto PECL libsodium aggiunge un wrapper per Sodium a beneficio degli sviluppatori PHP.

Anche aziende tecnologiche leader come Facebook, Discord, Malwarebytes e Valve usano libsodium per proteggere i propri utenti con connessioni veloci e sicure.

libsodium supporta l’algoritmo di crittografia XChaCha20 per cifrare e decifrare i dati, specialmente per la crittografia dei flussi. Allo stesso modo, l’estensione PECL libsodium supporta già XChaCha20, ma solo con il codice di autenticazione dei messaggi Poly1305.

Molte applicazioni PHP usano XChaCha20 direttamente per la crittografia dei flussi. Per semplificare le cose, a partire da PHP 8.1, avremo tre nuove funzioni per criptare o decriptare i dati con XChaCha20 senza autenticazione. Questa modalità è chiamata “modalità distaccata”.

Le nuove funzioni di XChaCha20 sono:

  • sodium_crypto_stream_xchacha20_keygen: Restituisce una chiave casuale sicura da usare con sodium_crypto_stream_xchacha20.
  • sodium_crypto_stream_xchacha20: Espande la chiave e il nonce in un keystream di byte pseudorandom.
  • sodium_crypto_stream_xchacha20_xor: Cripta un messaggio utilizzando un nonce e una chiave segreta (nessuna autenticazione).

Inoltre, ci sono due nuove costanti PHP definite nello spazio dei nomi globali:

  • SODIUM_CRYPTO_STREAM_XCHACHA20_KEYBYTES (assigned 32)
  • SODIUM_CRYPTO_STREAM_XCHACHA20_NONCEBYTES (assigned 24)

Usatelo con cautela, però. Dato che è senza autenticazione, l’operazione di decrittazione è vulnerabile ai comuni attacchi ciphertext.

Potete leggere altro sull’utilizzo e sui requisiti sulla pagina GitHub.

Nuova Classe IntlDatePatternGenerator

La libreria ICU sottostante di PHP permette di creare formati di data e ora localizzati, ma non è completamente personalizzabile.

Ad esempio, fino a PHP 8.0, potete creare formati di data e ora specifici per il locale utilizzando la costante predefinita IntlDateFormatter. Avete 6 modi per farlo:

  • IntlDateFormatter::LONG: Più lungo, come November 10, 2017 o 11:22:33pm
  • IntlDateFormatter::MEDIUM: Un po’ più corto, come Nov 10, 2017
  • IntlDateFormatter::SHORT: Solo numerico, come 10/11/17 o 11:22pm

Ognuno di questi ha anche la sua variante RELATIVE_, che imposta la formattazione della data in un intervallo limitato prima o dopo la data corrente. In PHP, i valori sono yesterday, today e tomorrow.

Supponiamo di voler utilizzare la versione lunga per l’anno e la versione breve per il mese, come 10/11/2017. Con PHP 8.0 non è possibile.

A partire da PHP 8.1, potete specificare i formati da usare per la data, il mese e l’ora grazie alla nuova classe IntlDatePatternGenerator. Potete lasciare l’ordine esatto di questi componenti al formatter.

Si noti che, anche se la classe ha solo la parola Date, è coerente con DateTimePatternGenerator di ICU. Ciò significa che potete utilizzarla anche per creare formati temporali flessibili. Per semplificare la denominazione, il team di PHP ha scelto di utilizzare il termine più breve IntlDatePatternGenerator.

Ecco un esempio offerto dalla RFC:

$skeleton = "YYYYMMdd";
 
$today = \DateTimeImmutable::createFromFormat('Y-m-d', '2021-04-24');
 
$dtpg = new \IntlDatePatternGenerator("de_DE");
$pattern = $dtpg->getBestPattern($skeleton);
echo "de: ", \IntlDateFormatter::formatObject($today, $pattern, "de_DE"), "\n";
 
$dtpg = new \IntlDatePatternGenerator("en_US");
$pattern = $dtpg->getBestPattern($skeleton), "\n";
echo "en: ", \IntlDateFormatter::formatObject($today, $pattern, "en_US"), "\n";
 
/*
de: 24.04.2021
en: 04/24/2021
*/

Nel codice precedente, la variabile skeleton definisce i particolari formati di data o ora. Tuttavia, il formattatore gestisce l’ordine del risultato finale.

Supporto del Formato Immagine AVIF

AVIF, o AV1 Image File Format, è un formato immagine relativamente nuovo senza diritti d’autore basato sul formato di codifica video AV1. Oltre ad offrire una maggiore compressione (e quindi dimensioni di file minori), supporta anche diverse caratteristiche come la trasparenza, HDR e altro.

Il formato AVIF è stato standardizzato solo di recente (8 giugno 2021). Questo ha aperto la strada ai browser, come Chrome 85+ e Firefox 86+, che hanno aggiunto il supporto per le immagini AVIF.

L’elaborazione delle immagini di PHP 8.1 e l’estensione GD aggiungono il supporto delle immagini AVIF.

Tuttavia, per includere questa funzionalità, è necessario compilare l’estensione GD con supporto AVIF. Potete farlo eseguendo i comandi qui sotto.

Per Debian/Ubuntu:

apt install libavif-dev

Per Fedora/RHEL:

dnf install libavif-devel

Questo installerà tutte le ultime dipendenze. Di seguito, potete compilare il supporto AVIF eseguendo il flag --with-avif con lo script ./configure.

./buildconf --force
./configure --enable-gd --with-avif

Se state avviando un nuovo ambiente da zero, puoi anche abilitare altre estensioni PHP qui.

Una volta installato, potete testare se il supporto AVIF è abilitato eseguendo il seguente comando nel terminale PHP:

php -i | grep AVIF

Se avete installato correttamente AVIF, vedrete questo risultato:

AVIF Support => enabled

Potete anche eseguire una chiamata gd_info() per recuperare un elenco di caratteristiche di GD, incluso il supporto della funzionalità AVIF Support.

L’aggiornamento di questa estensione GD di PHP 8.1 aggiunge anche due nuove funzioni che consentono di lavorare con le immagini AVIF: imagecreatefromavif e imageavif. Funzionano in modo simile alle rispettive controparti JPEG e PNG.

La funzione imagecreatefromavif restituisce un’istanza GdImage da una data immagine AVIF. Potete quindi utilizzare questa istanza per modificare o convertire l’immagine.

La funzione imageavif produce il file immagine AVIF. Ad esempio, potete utilizzarla per convertire un JPEG in AVIF:

$image = imagecreatefromjpeg('image.jpeg');
imageavif($image, 'image.avif');

Potete leggere di più su questa nuova funzione nella pagina GitHub.

Nuova Chiave $_FILES: full_path per il Caricamento delle Directory

PHP mantiene un gran numero di variabili predefinite per tenere traccia di varie cose. Una di queste è la variabile $_FILES che contiene un array associativo di elementi caricati tramite il metodo HTTP POST.

La maggior parte dei browser moderni supporta il caricamento di un’intera directory con i campi HTML per il caricamento dei file. Anche PHP <8.1 supportava questa funzionalità, ma con un importante avvertimento. Non si poteva caricare una cartella con la sua esatta struttura di directory o percorsi relativi perché PHP non passava queste informazioni all’array $_FILES.

In PHP 8.1 le cose cambiano, grazie all’aggiunta di una nuova chiave full_path all’array $_FILES. Con questi nuovi dati, è possibile memorizzare percorsi relativi o duplicare l’esatta struttura della directory sul server.

Potete testare queste informazioni emettendo l’array $FILES utilizzando il comando var_dump($_FILES);.

Ma procedete con cautela. Assicuratevi di proteggervi dagli attacchi standard di caricamento dei file.

Spacchettamento degli Array per gli Array con Chiavi a Stringa

PHP 7.4 ha aggiunto il supporto dello spacchettamento degli array con lo spread operatore di diffusione degli array (). È un’alternativa più veloce alla funzione array_merge(). Tuttavia, questa caratteristica era limitata agli array con chiave numerica, dato che lo spacchettamento degli array con chiave stringa causava conflitti durante la fusione degli array con chiavi duplicate.

Tuttavia, PHP 8 aveva già aggiunto il supporto degli argomenti con nome, rimuovendo questa limitazione. Quindi, lo spacchettamento degli array ora supporterà anche gli array con chiave stringa utilizzando la stessa sintassi:

$array = [...$array1, ...$array2];

Questo esempio tratto dalla RFC illustra come viene gestita la fusione di array con chiavi stringhe duplicate in PHP 8.1:

$array1 = ["a" => 1];
$array2 = ["a" => 2];
$array = ["a" => 0, ...$array1, ...$array2];
var_dump($array); // ["a" => 2]

Qui, la chiave stringa “a” appare tre volte prima della fusione tramite lo spacchettamento dell’array. Ma prevale solo il suo ultimo valore appartenente a $array2.

Notazione Esplicita dei Numeri Ottali

PHP supporta vari sistemi numerici, tra cui decimale (base-10), binario (base-2), ottale (base-8) ed esadecimale (base-16). Il sistema numerico decimale è quello predefinito.

Se volete usare qualsiasi altro sistema numerico, allora dovrete aggiungere ad ogni numero un prefisso standard:

  • Hex: prefisso 0x. (es. 17 = 0x11)
  • Binary: prefisso 0b. (es. 3 = 0b11)
  • Octal: prefisso 0. (es. 9 = 011)

Il prefisso del sistema numerico ottale è diverso dagli altri. Per standardizzare, molti linguaggi di programmazione stanno aggiungendo il supporto di una notazione numerica ottale esplicita: 0o o 0O.

A partire da PHP 8.1, potete riscrivere l’esempio mostrato sopra (cioè il numero 9 in base 10) nel sistema numerico ottale come 0o11 o 0O11.

0o16 === 14; // true
0o123 === 83; // true
 
0O16 === 14; // true
0O123 === 83; // true
 
016 === 0o16; // true
016 === 0O16; // true

Inoltre, questa nuova caratteristica si adatta anche al separatore letterale numerico underscore introdotto in PHP 7.4.

Si legga la RFC per un approfondimento su questa nuova caratteristica di PHP 8.1.

Supporto degli Algoritmi di Hash MurmurHash3 e xxHash

PHP 8.1 aggiunge il supporto degli algoritmi di hashing MurmurHash3 e xxHash. Non sono progettati per l’uso crittografico, ma forniscono comunque un’impressionante casualità, dispersione e unicità dell’output.

Questi nuovi algoritmi di hashing sono più veloci della maggior parte degli algoritmi di hashing di PHP. Infatti, alcune varianti di questi algoritmi di hashing sono più veloci del throughput della RAM.

Dato che PHP 8.1 aggiunge anche la possibilità di dichiarare parametri $options specifici per l’algoritmo, si può fare lo stesso con questi nuovi algoritmi. Il valore predefinito di questo nuovo parametro è []. Quindi, non influenzerà nessuna delle nostre funzioni hash esistenti.

Si può leggere di più su queste nuove caratteristiche di PHP 8.1 sulle rispettive pagine GitHub: MurmurHash3, xxHash, $options specifiche dell’algoritmo.

DNS-over-HTTPS (DoH)

DNS-over-HTTPS (DoH) è un protocollo per la risoluzione del DNS tramite HTTPS. Utilizzando HTTPS per crittografare i dati tra il client e il resolver DNS, DoH aumenta la privacy e la sicurezza dell’utente prevenendo gli attacchi MitM.

A partire da PHP 8.1, è possibile utilizzare l’estensione Curl per specificare un server DoH. Richiede che PHP sia compilato con le versioni libcurl 7.62+. Questo non è un problema per la maggior parte dei sistemi operativi più utilizzati, incluse le distro Linux, poiché spesso includono Curl 7.68+.

Potete configurare l’URL del server DoH specificando l’opzione CURLOPT_DOH_URL.

$doh = curl_init('https://kinsta.com');
curl_setopt($doh, CURLOPT_DOH_URL, 'https://dns.google/dns-query');
curl_exec($doh);

Nell’esempio precedente, abbiamo utilizzato il server DNS pubblico di Google. Si noti anche l’utilizzo di https:// in tutti gli URL utilizzati. Assicuratevi di configurarlo perfettamente perché non c’è un server DNS predefinito a cui ricorrere in Curl.

Potete anche scegliere da una lista di server DoH pubblici inclusi nella documentazione di Curl.

Inoltre, il riferimento CURLOPT_DOH_URL della documentazione di Curl spiega accuratamente come utilizzare i vari argomenti.

Caricamento di file da stringhe con CURLStringFile

L’estensione PHP Curl supporta richieste HTTP(S) con upload di file. A questo scopo usa la classe CURLFile, che accetta un URI o un percorso di file, un tipo mime e il nome finale del file.

Tuttavia, con la classe CURLFile, potete solo accettare il percorso del file o l’URI, ma non il contenuto del file stesso. Nei casi in cui avevate già il file da caricare in memoria (ad esempio immagini elaborate, documenti XML, PDF), dovevate utilizzare le URI data:// con codifica Base64.

Ma libcurl supporta già una soluzione più semplice per accettare il contenuto del file. La nuova classe CURLStringFile aggiunge il supporto proprio di questo.

Potete leggere la pagina su GitHub se volete saperne come è implementato in PHP 8.1.

Nuova Costante MYSQLI_REFRESH_REPLICA

L’estensione mysqli di PHP 8.1 aggiunge la nuova costante MYSQLI_REFRESH_REPLICA. È equivalente alla costante esistente MYSQLI_REFRESH_SLAVE.

Questa novità è stata apprezzata in MySQL 8.0.23 per affrontare l’insensibilità razziale nel vocabolario tecnico (gli esempi più comuni sono “slave” e “master”).

Dovreste notare che la vecchia costante non è stata rimossa o deprecata. Gli sviluppatori e le applicazioni possono continuare ad usarla. Questa nuova costante è solo un’opzione per sviluppatori e aziende che vogliono lasciarsi alle spalle questa terminologia.

Miglioramenti delle Prestazioni con la Inheritance Cache

La Inheritance Cache è una nuova aggiunta a opcache che elimina l’overhead dell’ereditarietà delle classi PHP.

Le classi PHP sono compilate e messe in cache da opcache separatamente. Tuttavia, sono già collegate a run-time su ogni richiesta. Questo processo può comportare diversi controlli di compatibilità e prendere in prestito metodi/proprietà/constanti da classi madri e tratti.

Di conseguenza, l’esecuzione richiede molto tempo, anche se il risultato è lo stesso per ogni richiesta.

La Inheritance Cache collega tutte le classi dipendenti uniche (genitore, interfacce, tratti, tipi di proprietà, metodi) e memorizza i risultati nella memoria condivisa opcache. Dato che questo avviene solo una volta, l’ereditarietà richiede un minor numero di istruzioni.

Inoltre, rimuove le limitazioni per le classi immutabili, come le costanti non risolte, le proprietà tipizzate e i controlli dei tipi covarianti. Così, tutte le classi memorizzate nella opcache sono immutabili, riducendo ulteriormente il numero di istruzioni richieste.

Tutto sommato, questa novità offre benefici significativi in termini di prestazioni. Dimitry Stogov, l’autore di questa patch, ha rilevato un miglioramento dell’8% sul programma base di Symfony “Hello, World!”. Non vediamo l’ora di testarla nei nostri prossimi benchmark PHP.

Sintassi Callable di Prima Classe

PHP 8.1 aggiunge una sintassi callable di prima classe per sostituire le codifiche esistenti che utilizzano stringhe e array. Oltre a creare una Closure più pulita, questa nuova sintassi è anche accessibile dagli strumenti di analisi statica e rispetta lo scopo dichiarato.

Ecco alcuni esempi presi dalla RFC:

$fn = Closure::fromCallable('strlen');
$fn = strlen(...);
 
$fn = Closure::fromCallable([$this, 'method']);
$fn = $this->method(...)
 
$fn = Closure::fromCallable([Foo::class, 'method']);
$fn = Foo::method(...);

Qui tutte le coppie di espressioni sono equivalenti. La sintassi a tre punti () è simile alla sintassi di spacchettamento degli argomenti (...$args). Tranne che qui, gli argomenti non sono ancora riempiti.

Modifiche in PHP 8.1

PHP 8.1 include anche modifiche alla sintassi e alle funzionalità esistenti. Vediamole insieme:

La PHP Interactive Shell Richiede l’Estensione Readline

L’estensione readline di PHP abilita funzionalità interattive della shell come la navigazione, il completamento automatico, l’editing e altro. Sebbene sia inclusa in PHP, non è abilitata di default.

Potete accedere alla shell interattiva di PHP utilizzando l’opzione a riga di comando -a di PHP CLI:

php -a

Interactive shell

php >
php > echo "Hello";
Hello
php > function test() {
php { echo "Hello";
php { }
php > test();
Hello

Prima di PHP 8.1, si poteva aprire la shell interattiva usando PHP CLI anche senza l’abilitazione dell’estensione readline. Come previsto, le funzionalità interattive della shell non funzionavano, e ciò rendeva l’opzione -a priva di significato.

In PHP 8.1 CLI, la shell interattiva esce con un messaggio di errore se non avete abilitato l’estensione readline.

php -a
Interactive shell (-a) requires the readline extension.

Modalità di Errore Predefinita di MySQLi Impostata su Exceptions

Prima di PHP 8.1, MySQLi di default rendeva silenti gli errori. Questo comportamento portava spesso ad avere codice che non seguiva una gestione rigorosa degli errori e delle eccezioni. Gli sviluppatori dovevano implementare le proprie funzioni esplicite di gestione degli errori.

PHP 8.1 cambia questo comportamento di MySQLi impostando la modalità predefinita di segnalazione degli errori in modo che venga lanciata un’eccezione.

Fatal error: Uncaught mysqli_sql_exception: Connection refused in ...:...

Trattandosi di un cambiamento radicale, per le versioni di PHP <8.1, è necessario impostare esplicitamente la modalità di gestione degli errori utilizzando la funzione mysqli_report prima di effettuare la prima connessione a MySQLi. In alternativa, potete fare lo stesso selezionando il valore di segnalazione degli errori con un’istanza di mysqli_driver.

La RFC segue una modifica simile introdotta in PHP 8.0.

Fine Riga Personalizzabile per le Funzioni di Scrittura CSV

Prima di PHP 8.1, le funzioni di scrittura CSV incorporate in PHP, fputcsv e SplFileObject::fputcsv, aggiungevano \n (o il carattere Line-Feed) alla fine di ogni riga.

PHP 8.1 aggiunge a queste funzioni il supporto di un nuovo parametro chiamato eol. Potete utilizzarlo per passare un carattere di fine riga configurabile. Di default usa ancora il carattere \n. Quindi, potete continuare ad usarlo nel vostro attuale codice.

Per i caratteri di fine riga si applicano le regole standard di escape dei caratteri. Se volete utilizzare \r, \n, o \r\n come caratteri di EOL, dovete racchiuderli in doppi apici.

Ecco la pagina GitHub che traccia questa novità.

Nuove Restrizioni per l’Operatore version_compare

La funzione version_compare() di PHP confronta due stringhe di numeri di versione. Questa funzione accetta un terzo argomento facoltativo chiamato operator per testare una particolare relazione.

Sebbene non sia trattato esplicitamente nella documentazione, prima di PHP 8.1, si poteva impostare questo parametro su un valore parziale (ad esempio g, l, n) senza incorrere in un errore.

PHP 8.1 aggiunge restrizioni più severe all’argomento operator della funzione version_compare() per superare questa situazione. Gli unici operatori che ora si possono utilizzare sono:

  • ==, =, e eq
  • !=, <>, e ne
  • > e gt
  • >= e ge
  • < e lt
  • <= e le

Niente più valori parziali dell’operatore.

Le Funzioni di Encoding e Decoding HTML ora Usano ENT_QUOTES | ENT_SUBSTITUTE

Le entità HTML sono rappresentazioni testuali di caratteri che altrimenti verrebbero interpretati come HTML. Pensate a caratteri come < e > utilizzati per definire i tag HTML (per esempio <a>, <h3>, <script>).

L’entità HTML per < è & lt; (simbolo minore di) e > è & gt; (simbolo maggiore di). Potete usare queste entità HTML in modo sicuro in un documento HTML senza innescare il motore di rendering del browser.

Nota: Rimuovete lo spazio tra “&” e “amp”.

Potete usare queste entità HTML in modo sicuro in un documento HTML senza innescare il motore di rendering del browser.

Ad esempio, & lt;script& gt; sarà visualizzato come <script> nel browser, invece di essere interpretato come un tag HTML.

Prima di PHP 8.1, le funzioni htmlspecialchars() e htmlentities() convertivano simboli come ", < , > , e & nelle loro rispettive entità HTML. Ma di default non convertivano il carattere delle virgolette singole (') nella sua entità HTML. Inoltre, restituivano una stringa vuota se c’era un UTF-8 malformato nel testo.

In PHP 8.1., queste funzioni di codifica e decodifica HTML (e le loro funzioni correlate) di default convertiranno anche i caratteri delle virgolette singole nella loro entità HTML.

E se il testo dato contiene caratteri non validi, le funzioni li sostituiranno con un carattere di sostituzione Unicode (�) invece di restituire una stringa vuota. Tutto questo avviene da PHP 8.1 cambiando le firme di queste funzioni in ENT_QUOTES | ENT_SUBSTITUTE piuttosto che ENT_COMPAT.

La maggior parte dei framework usa già ENT_QUOTES come valore predefinito del flag. Quindi, non vedrete molte differenze da questa modifica. Tuttavia, il nuovo flag ENT_SUBSTITUTE non è molto usato. PHP 8.1 farà sì che i caratteri UTF-8 non validi vengano sostituiti con il carattere � invece di restituire una stringa vuota.

Avviso su Chiamate Illegali di Funzioni Compatte

La funzione compact() di PHP è davvero utile. Potete utilizzarla per creare un array con le variabili usando i rispettivi nomi e valori.

Considerate, ad esempio, il seguente codice:

$animal = 'Cat';
$sound = 'Meow';
$region = 'Istanbul';
compact('animal', 'sound', 'region');
// ['animal' => "Cat", 'sound' => "Meow", 'region' => "Istanbul"]

La documentazione della funzione compact afferma che questa accetta solo parametri stringa o array con valori stringa. Tuttavia, prima di PHP 7.3, qualsiasi stringa che non è impostata sarebbe stata silenziosamente saltata.

PHP 7.3 ha modificato la funzione compact() in modo che venga emesso una nota quando si usano variabili non definite. PHP 8.1 fa un passo avanti e lancia un avviso.

Si legga la pagina GitHub per capire come si è giunti a questa modifica.

Nuove Migrazioni da Risorse a Oggetti di Classe

Uno degli obiettivi a lungo termine di PHP è quello di allontanarsi dalle risorse per muoversi verso oggetti di classe standard.

Per ragioni storiche, gli oggetti risorsa sono utilizzati ampiamente nelle applicazioni PHP. Quindi, la migrazione delle risorse agli oggetti di classe deve essere il meno distruttiva possibile. PHP 8.1 migra cinque di queste risorse:

La Risorsa file_info Migrata agli Oggetti finfo

La classe finfo di PHP offre un’interfaccia orientata agli oggetti per le funzioni fileinfo. Tuttavia, l’utilizzo delle funzioni finfo restituisce oggetti resource con il tipo file_info invece che un’istanza della classe finfo stessa.

PHP 8.1 risolve questa anomalia.

Risorse IMAP Migrate in oggetti di classe IMAP\Connection

In linea con l’obiettivo della migrazione da risorsa a oggetto, la nuova classe IMAP\Connection minimizza i potenziali cambiamenti di rottura quando PHP modificherà eventualmente i dettagli di implementazione della classe.

Questa nuova classe è anche dichiarata final, quindi non è permesso extend.

Si legga di più sulla sua implementazione sulla pagina GitHub.

Le Risorse di Connessione FTP Sono ora Oggetti di Classe FTP\Connection

In PHP <8.1, se si crea una connessione FTP con le funzioni ftp_connect() o ftp_ssl_connect(), si ottiene un oggetto risorsa di tipo ftp.

Per rimediare, PHP 8.1 aggiunge la nuova classe FTP\Connection. E come per la classe IMAP\Connection, è anche dichiarata final per evitare che venga estesa.

Si può approfondire sull’implementazione nella pagina GitHub.

Identificatori di Font Migrati in Oggetti di Classe GdFont

L’estensione GD di PHP fornisce la funzione imageloadfont() per caricare una bitmap definita dall’utente e restituire il suo ID di risorsa font-identifier (un intero).

In PHP 8.1, questa funzione restituirà invece un’istanza della classe GdFont. Inoltre, per far sì che la migrazione avvenga senza problemi, tutte le funzioni che prima accettavano un ID risorsa da imageloadfont() ora prenderanno i nuovi oggetti di classe GdFont.

Si legga anche la pagina GitHub.

Risorse LDAP Migrate a Oggetti

LDAP, o Lightweight Directory Access Protocol, è utilizzato per accedere a “Directory Servers”. Come una struttura di directory su disco rigido, è un database unico che contiene dati in una struttura ad albero.

PHP include un’estensione LDAP che accettava o restituiva oggetti resource prima di PHP 8.1. Tuttavia, ora sono tutti migrati senza problemi alle nuove istanze di classe. I tipi di resource che sono stati migrati sono:

  • risorsa ldap link all’oggetto di classe \LDAP\Connection
  • risorsa ldap result all’oggetto di classe \LDAP\Result
  • risorsa ldap result entry all’oggetto di classe \LDAPResultEntry

Si legga la pagina GitHub per informazioni più dettagliate su questa migrazione.

Le Risorse Pspell Sono Ora Oggetti di Classe

L’estensione Pspell di PHP permette di controllare l’ortografia e i suggerimenti di parole.

PHP <8.1 utilizzava i tipi di oggetti risorsa pspell e pspell config con un identificatore intero. Questi due oggetti risorsa sono ora sostituiti da oggetti di classe PSpell\Dictionary e PSpell\Config.

Come le migrazioni precedenti, tutte le funzioni Pspell che prima accettavano o restituivano identificatori di oggetti risorsa prenderanno le nuove istanze di oggetti di classe.

Si faccia riferimento alla pagina GitHub per maggiori informazioni.

Deprecazioni in PHP 8.1

PHP 8.1 depreca molte delle precedenti funzionalità. Il seguente elenco fornisce una breve panoramica delle funzionalità deprecate a partire da PHP 8.1:

Impossibile Passare null a Parametri di Funzioni Interne Non-Nullable

A partire da PHP 8.0, le funzioni interne accettano in modo silente valori null anche per argomenti non-nullable. Lo stesso non vale per le funzioni definite dall’utente – queste accettano null solo per gli argomenti nullable.

Si consideri questo esempio:

var_dump(str_contains("foobar", null));
// bool(true)

Qui, il valore null viene silentemente convertito in una stringa vuota. Così, il risultato è true.

Questa RFC mira a uniformare il comportamento delle funzioni interne in modo che venga lanciato un avviso di deprecazione.

var_dump(str_contains("foobar", null));
// Deprecated: Passing null to argument of type string is deprecated

La deprecazione diventerà un TypeError nella prossima major version di PHP (cioè PHP >=9.0), rendendo il comportamento delle funzioni interne coerente con le funzioni definite dall’utente.

Uso Ristretto di $GLOBALS

La variabile $GLOBALS di PHP fornisce un riferimento diretto alla tabella interna dei simboli. Supportare questa funzionalità è complesso e influisce sulle prestazioni delle operazioni sugli array. Inoltre, era utilizzato raramente.

Come da RFC, ora non è più permesso modificare indirettamente $GLOBALS. Questa modifica non è retrocompatibile.

L’impatto è relativamente basso:

Nei primi 2k pacchetti di composer ho trovato 23 casi in cui si utilizza $GLOBALS senza dereferenziarlo direttamente. Sulla base di un’ispezione sommaria, ci sono solo due casi in cui $GLOBALS non è usato in sola lettura.

Tuttavia, l’utilizzo in sola lettura di $GLOBALS continua a funzionare come al solito. Ciò che non è più supportato è la scrittura su $GLOBALS nel suo complesso. Come risultato, ci si può aspettare un leggero miglioramento delle prestazioni, specialmente quando si lavora con gli array ordinari di PHP.

Dichiarazioni Tipi di Ritorno per Funzioni Interne

PHP 8.0 ha permesso agli sviluppatori di dichiarare parametri e tipi di ritorno per la maggior parte delle funzioni e dei metodi interni. Questo è stato possibile grazie a varie RFC come gli errori di tipo coerenti per le funzioni interne, Union Types 2.0 e Mixed Type v2.

Tuttavia, ci sono molti casi in cui le informazioni sul tipo possono mancare. Questi includono un tipo con risorse, parametri out pass-by-ref, tipo di ritorno di metodi non finali e funzioni o metodi che non analizzano i parametri secondo le regole generali. Per i dettagli, si faccia riferimento alla RFC.

Questa RFC affronta solo il problema del tipo di ritorno dei metodi non finali. Tuttavia, piuttosto che eliminarli del tutto immediatamente, il team di PHP stabilisce un percorso di migrazione graduale per permettere di aggiornare i codebase con i relativi tipi di ritorno dei metodi.

I tipi di ritorno dei metodi interni non deprecati – quando possibile – sono dichiarati in modo provvisorio in PHP 8.1, e diventeranno obbligatori in PHP 9.0. Significa che nelle versioni di PHP 8.x, un avviso “deprecato” viene sollevato durante i controlli di ereditarietà quando un metodo interno viene sovrascritto in modo che i tipi di ritorno siano incompatibili e PHP 9.0 li renderà un errore fatale.

Se vedete questo avviso di deprecazione dopo l’aggiornamento a PHP 8.1, assicuratevi di aggiornare i tipi di ritorno dei vostri metodi.

Interfaccia Serializzabile Deprecata

PHP 7.4 ha introdotto il meccanismo di serializzazione degli oggetti personalizzati con due nuovi metodi magici: __serialize() e __unserialize(). Questi nuovi metodi mirano a sostituire l’interfaccia Serializable interrotta.

Questa RFC propone di finalizzare quella decisione stabilendo un piano per la rimozione finale di Serializable.

In PHP 8.1, se implementate l’interfaccia Serializable senza implementare i metodi __serialize() e __unserialize(), PHP lancia un avvertimento “Deprecated”.

Deprecated: The Serializable interface is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in ... on line ...

Se supportate PHP <7.4 e PHP >=7.4, dovreste implementare sia l’interfaccia Serializable che i nuovi metodi magici. Nelle versioni di PHP >=7.4, i metodi magici avranno la precedenza.

Deprecate le Conversioni da float a int non Compatibili

PHP è un linguaggio tipizzato dinamicamente. Come tale, ci sono molti casi in cui la coercizione dei tipi si verifica naturalmente. La maggior parte di queste coercizioni sono innocue ed estremamente comode.

Tuttavia, quando un numero float viene convertito in un integer, spesso si ha una perdita di dati. Per esempio, quando il float 3.14 viene convertito in un intero 3, perde il suo valore frazionario.

Lo stesso accade quando il float è al di fuori dell’intervallo di interi della piattaforma, o quando una stringa float viene convertita in un intero.

PHP 8.1 rettifica questo comportamento e porta la coercizione dinamica dei tipi più in linea con la maggior parte dei linguaggi di programmazione moderni. L’obiettivo è di rendere tali coercizioni prevedibili e intuitive.

In PHP 8.1, vedrete un avviso di deprecazione quando un float non compatibile è implicitamente forzato a int. Ma cosa costituisce un float compatibile con un intero? La RFC risponde così:

Un float si dice compatibile con gli interi se possiede le seguenti caratteristiche:

  • È un numero (cioè non NaN o Infinito)
  • È nell’intervallo di un intero PHP (dipende dalla piattaforma)
  • Non ha parte frazionaria

Questo avviso di deprecazione si trasformerà in un TypeError nella prossima major release di PHP (cioè la 9.0).

Deprecati Il Metodo mysqli::get_client_info e mysqli_get_client_info($param)

L’API del client MySQL definisce due costanti: client_info (string) e client_version (int). MySQL Native Driver (MySQLnd) è parte del sorgente ufficiale di PHP e lega queste costanti alla versione di PHP. In libmysql, queste rappresentano la versione della libreria client al momento della compilazione.

Prima di PHP 8.1, mysqli esponeva queste costanti in 4 modi: proprietà mysqli_driver, proprietà mysqli, funzione mysqli_get_client_info() e metodo mysqli::get_client_info. Ma non c’è un metodo per client_version.

MySQLnd espone queste costanti a PHP in 2 modi: una costante e una chiamata di funzione. Per unificare i metodi di accesso di mysqli con queste stesse due opzioni, PHP 8.1 depreca queste altre due opzioni:

  • metodo get_client_info nella classe mysqli. Al suo posto potete semplicemente usare la funzione mysqli_get_client_info().
  • mysqli_get_client_info() con parametri. Invocate la funzione senza parametri per evitare l’avviso di deprecazione.

Si legga la pagina GitHub.

Sono Deprecate Tutte le Funzioni mhash*() (Estensione hash)

PHP 5.3 aveva integrato le funzioni mhash*() in ext/hash come livello di compatibilità per ext/mhash. Più tardi, PHP 7.0 aveva rimosso ext/mhash.

A differenza delle funzioni hash_*(), le funzioni mhash*() non sono sempre disponibili. Bisogna abilitarle separatamente durante la configurazione di PHP.

In PHP 7.4, l’estensione hash è stata distribuita insieme a PHP, diventando un’estensione predefinita di PHP. Tuttavia, supportava ancora l’abilitazione dell’opzione --enable-mhash per ragioni di compatibilità.

Il team di PHP ha deciso di deprecare le funzioni mhash*() a partire da PHP 8.1 e di rimuoverle del tutto in PHP 9.0. Le funzioni deprecate sono mhash(), mhash_keygen_s2k(), mhash_count(), mhash_get_block_size() e mhash_get_hash_name(). Al loro posto è possibile utilizzare le funzionalità standard di ext/hash.

Deprecate Entrambe le Impostazioni INI filter.default e filter.default_options

Le impostazioni INI filter.default di PHP permettono di applicare un filtro a tutti i superglobal, cioè i dati GPCRS ($_GET, $_POST, $_COOKIE, $_REQUEST e $_SERVER).

Ad esempio, potete impostare filter.default=magic_quotes o filter.default=add_slashes (in base alla versione di PHP) per far risorgere la controversa e insicura funzionalità delle magic quotes di PHP (rimossa in PHP 5.4).

L’impostazione INI filter.default offre funzionalità aggiuntive permettendo l’utilizzo di molti più filtri, peggiorando le cose ancora di più. Ad esempio, un’altra opzione – filter.default=special_chars – abilita le virgolette magiche solo per l’HTML. C’è minore consapevolezza di queste impostazioni.

A partire da PHP 8.1 sarà emesso un avviso di deprecazione se filter.default è impostato su qualsiasi valore diverso da unsafe_raw (il valore predefinito). Non vedrete nessun avviso di deprecazione separato per filter.default_options, ma entrambe queste impostazioni INI saranno rimosse a partire da PHP 9.0.

In alternativa, potete iniziare ad utilizzare la funzione filter_var(). Questa filtra le variabili con il filtro specificato.

Deprecato autovivification su false

PHP permette l’autovivificazione (autocreazione di array da valori falsi). Questa funzionalità è molto utile se la variabile è indefinita.

Ma creare automaticamente un array quando il valore è falso o nullo non è l’ideale.

Questa RFC non permette l’autovivificazione da valori falsi. Si noti, però, che l’autovivificazione da variabili indefinite e nulle è ancora consentita.

A partire da PHP 8.1, accodare a una variabile di tipo false causa l’emissione un avviso di deprecazione:

Deprecated: Automatic conversion of false to array is deprecated in

PHP 9.0 emetterà un errore fatale, cosa che è identica per altri tipi scalari.

Deprecata La Proprietà mysqli_driver->driver_version

La proprietà mysqli_driver->driver_version dell’estensione MySQLi non viene aggiornata da 13 anni. Nonostante i molti cambiamenti al driver apportati da allora, questa restituisce ancora il vecchio valore della versione del driver, e ciò rende questa proprietà priva di significato.

Da PHP 8.1, la proprietà mysqli_driver->driver_version è deprecata.

Altre Modifiche Minori

Ci sono molte altre deprecazioni in PHP 8.1. Elencarle tutte qui sarebbe estenuante. Consigliamo di controllare direttamente l’RFC per queste deprecazioni minori.

La pagina GitHub di PHP contiene una guida PHP 8.1 UPGRADE NOTES. Questa elenca tutte le modifiche di cui dovreste tener conto prima di aggiornare a PHP 8.1.

Riepilogo

Non manca molto a PHP 8.1 e promette già di superare il suo predecessore, il che non è una cosa da poco. Pensiamo che le funzionalità più entusiasmanti di PHP 8.1 siano Enums, Fibers, Pure Intersection Types e i miglioramenti delle prestazioni. Non vediamo l’ora di mettere PHP 8.1 alla prova e fare il benchmark dei vari framework PHP e dei CMS.

Salvate questo post tra preferiti come futuro riferimento.

Quale funzionalità di PHP 8.1 preferite? Condividete le vostre considerazioni con la community nella sezione dei commenti.

Salman Ravoof

Salman Ravoof is a self-taught web developer, writer, creator, and a huge admirer of Free and Open Source Software (FOSS). Besides tech, he's excited by science, philosophy, photography, arts, cats, and food. Learn more about him on his website, and connect with Salman on Twitter.