Il gruppo PHP ha rilasciato la versione 8.5 del linguaggio di scripting open source che alimenta gran parte del web, compresi i siti che utilizzano il CMS WordPress.

Il rilascio di PHP 8.5 a novembre ha segnato il secondo anno dell’impegno della community PHP a fornire aggiornamenti importanti con cadenza annuale, seguiti da due anni interi di supporto attivo per ogni release.

Anche se la versione 8.5 è nuova di zecca, l’abbiamo già analizzata nel nostro benchmarking annuale di PHP dietro a una serie di piattaforme e framework CMS popolari.

Se hai intenzione di migrare le applicazioni PHP alla versione 8.5, è bene che tu sappia cosa è cambiato in quest’ultima release. Tra le novità ci sono nuove funzionalità che potresti sfruttare per migliorare il tuo codice e vecchie funzionalità che gli sviluppatori di PHP si stanno preparando a rimuovere.

Ecco quali sono i punti salienti della nuova versione:

Nuove funzionalità e miglioramenti in PHP 8.5

Iniziamo con le nuove aggiunte al codice base di PHP. Queste modifiche di solito iniziano come richieste di commenti (Requests for Comments, RFC) che alla fine potrebbero essere approvate e assegnate a una futura release di PHP.

Le nuove funzionalità descritte di seguito sono quelle che stanno catturando la maggior parte dell’attenzione intorno a PHP 8.5.

Chiamate di funzione a catena con l’operatore pipe

Un nuovo operatore pipe (|>) concatena le chiamate di funzione in un modo che risulterà vagamente familiare ai programmatori JavaScript. La pipe opera da sinistra a destra, passando un singolo valore lungo la catena a ogni passo.

Con le versioni precedenti di PHP, i programmatori potevano realizzare un’operazione simile annidando le funzioni o eseguendo una serie di chiamate di funzione su ogni valore restituito.

Ecco un semplice esempio che utilizza il nuovo operatore pipe:

$text = ' New-in-php-8.4 ';

$result = $text
    |> trim(...)
    |> (fn($str) => str_replace('4', '5', $str))
    |> (fn($str) => str_replace('-', ' ', $str))
    |> strtoupper(...);

var_dump($result);
// string(14) "NEW IN PHP 8.5"

(Nota che stiamo utilizzando la sintassi di prima classe (...) introdotta in PHP 8.1 con le chiamate di funzione trim() e strtoupper() )

La catena di pipe qui sopra potrebbe essere scritta su una sola riga, ma la leggibilità dovrebbe essere uno dei vantaggi di questo nuovo operatore.

Quanto sopra equivale ad annidare queste operazioni (in ordine inverso) in questo modo:

$text = " New-in-php-8.4 ";

$result = strtoupper(
    str_replace(‘-, ' ',
        str_replace('4', '5', 
            trim($text)
         )
     )
);

In alternativa, un developer avrebbe potuto completare l’operazione nelle versioni precedenti di PHP in questo modo:

$text = " New-in-php-8.4 ";

$result = trim($text);
$result = str_replace('4', '5', $result);
$result = str_replace(‘-, ' ', $result);
$result = strtoupper($result);

Analisi degli URL con la nuova estensione URI

Gli URL (noti anche come URI per i più esigenti) sono essenziali per la navigazione sul web, ma la funzione parse_url(), integrata in PHP dalla versione 4, ha notoriamente problemi con gli input malformati che possono portare a errori quando si tenta di manipolare o convalidare gli indirizzi dei siti web.

Per migliorare il parsing degli URL, PHP 8.5 incorpora le librerie uriparser e Lexbor per supportare rispettivamente gli standard RFC 3986 e WHATWG URL.

Puoi invocare la libreria uniparser iniziando a lavorare con la nuova estensione URI in questo modo:

$uri = new UriRfc3986Uri("https://kinsta.com/blog/php-8-5/"); 

echo $uri->getScheme();       // https
echo $uri->getHost();         // kinsta.com
echo $uri->getPath();         // /blog/php-8-5

In alternativa, puoi scegliere la libreria Lexbor WHATWG URL in questo modo:

$uri = new UriWagWgUrl("https://kinsta.com/blog/php-8-5/"); 

echo $uri->getScheme();       // https
echo $uri->getUnicodeHost();  // kinsta.com
echo $uri->getAsciiHost();    // kinsta.com
echo $uri->getPath();         // /blog/php-8-5

Gli esempi precedenti sono i più elementari. Le due librerie rappresentate dall’estensione URI in PHP 8.5 condividono alcune funzionalità ma presentano anche differenze significative.

Una differenza importante è che la libreria RFC 3986 supporta sia le rappresentazioni “grezze” che quelle “normalizzate-decodificate” degli URI. Questo può essere utile quando si lavora con input e output codificati in percentuale. Utilizzati in un browser, ad esempio, questi due URI sono identici:

Nelle versioni precedenti di PHP, si poteva iniziare con rawurldecode() e rawurlencode() (che sono anche conformi alla RFC 3986), ma la nuova estensione è pronta a lavorare con tutti i componenti degli URI, indipendentemente dal fatto che siano codificati o meno.

Ecco alcuni esempi tratti direttamente dalla RFC che sta alla base della nuova API di parsing:

$uri = new UriRfc3986Uri("https://%61pple:p%61ss@ex%61mple.com/foob%61r?%61bc=%61bc");
  
echo $uri->getRawUserInfo();  // %61pple:p%61ss
echo $uri->getUserInfo();     // apple:pass
 
echo $uri->getRawUsername();  // %61pple
echo $uri->getUsername();     // apple
 
echo $uri->getRawPassword();  // p%61ss
echo $uri->getPassword();     // pass
 
echo $uri->getRawHost();      // ex%61mple.com
echo $uri->getHost();         // example.com
 
echo $uri->getRawPath();      // /foob%61r
echo $uri->getPath();         // /foobar
 
echo $uri->getRawQuery();     // %61bc=%61bc
echo $uri->getQuery();        // abc=abc

Quando si utilizza la libreria URL WHATWG con la nuova estensione, tutti gli URI sono trattati come “grezzi”, quindi non c’è una serie di funzioni separate per supportare la formattazione alternativa. Tuttavia, la libreria è in grado di convertire i caratteri ASCII e Unicode spesso presenti negli URI.

Più precisione con la nuova direttiva INI max_memory_limit

Si dice che da grandi poteri derivino grandi responsabilità. Se questo potere include la scelta della quantità di memoria del server che la tua applicazione PHP può tentare di utilizzare, potresti essere tu responsabile dei crash dell’applicazione quando i processi consumano più memoria di quella disponibile.

Una tipica installazione di PHP comprende un file php.ini con informazioni di configurazione che includono una direttiva che specifica il limite di consumo di memoria per ogni processo (o thread) PHP. Una direttiva INI comune per un limite di memoria di 128 MB si presenta come segue:

// php.ini
memory_limit 128M

Su alcune piattaforme di hosting, chi sviluppa applicazioni PHP può ignorare memory_limit al volo utilizzando la funzione ini_set() nel codice:

ini_set(‘memory_limit’, ‘256M’);
 
// Start code that requires up to 256 MB of memory

È anche possibile passare alla funzione il valore -1, come ini_set('memory_limit', '-1'), per non imporre alcun limite.

Sovrascrivere la direttiva INI per un limite di memoria può essere rischioso per gli sviluppatori che non conoscono bene le configurazioni di memoria dei server su cui gireranno le loro applicazioni. Se uno o più thread PHP tentano di consumare più della memoria totale, il risultato può essere un crash dell’applicazione senza preavviso.

PHP 8.5 aggiunge una direttiva INI max_memory_limit che funge da limite massimo, anche nelle configurazioni in cui gli sviluppatori hanno accesso a init_set() per modificare l’uso della memoria nel codice.

Ecco degli esempi di voci nel file php.ini di un’installazione di PHP 8.5:

// php.ini
max_memory_limit 256M
memory_limit 128M

Con un max_memory_limit di 256 MB, ecco cosa succede nel codice PHP:

ini_set('memory_limit', '256M');  // This is OK
ini_set('memory_limit', '512M');  // Fail with warning
ini_set('memory_limit', '-1');    // Fail with warning

Il tentativo di impostare un nuovo limite di memoria di 512 MB (o illimitato) non avrà successo. Al contrario, PHP imposterà il limite di memoria al valore assegnato a max_memory_limit nel file php.ini ed emetterà un avviso. (Il messaggio di avviso potrebbe essere visualizzato sullo schermo e registrato, a seconda delle impostazioni di segnalazione degli errori dell’installazione PHP).

Un approccio saggio per chi sviluppa con PHP 8.5 sarebbe quello di utilizzare la funzione ini_get() per verificare se il nuovo limite massimo è stato definito, come ini_get('max_memory_limit'), e quindi regolarsi in base al valore restituito. Con le versioni di PHP precedenti alla 8.5, questa chiamata restituirebbe tranquillamente false.

Lettura del primo o dell’ultimo valore di un array

Alzi la mano chi pensa che PHP disponga già di funzioni per leggere i valori memorizzati come primi o ultimi membri di un array.

A quanto pare, non è così. Ma da PHP 7.3 esistono funzioni per scoprire la prima e l’ultima chiave di un array. Quindi, per trovare il primo e l’ultimo valore, si possono utilizzare le funzioni array_key_first() o array_key_last() e poi usare le chiavi restituite per fare riferimento ai valori che stiamo cercando:

$array = ["One", "Two", "Three"];

echo $array[array_key_first($array)]; // "One"

PHP 8.5 elimina un passaggio per questo compito e permette di raggiungere i valori direttamente con le nuove funzioni array_first() e array_last().

È tutto molto semplice:

$array = ["One", "Two", "Three"];

echo array_first($array);  // "One"
echo array_last($array);   // "Three"
echo array_last([]);       // null

Qui sopra, vediamo che un array vuoto restituirà null, ma questo non conferma che l’intero array sia vuoto, poiché un valore dell’array può essere nullo:

echo array_last([1, 2, null]); // null

L’importanza di usare il valore di ritorno di una funzione

PHP 5.8 aggiunge un nuovo attributo #[NoDiscard] che indica che il valore di ritorno di una funzione potrebbe essere critico. PHP verificherà che il valore di ritorno sia consumato in qualche modo e, in caso contrario, emetterà un avviso.

Un semplice esempio:

#[NoDiscard("this message property will be appended to the built-in warning.")]
function foo(): string {
    return 'bar';
}

// Warning:
// The return value of function foo() is expected to be consumed,
// this message property will be appended to the built-in warning.
foo();

// This will not trigger a warning:
$result = foo();

// Also satisfactory is the (void) cast:
(void) foo();

Nell’esempio precedente, il valore di ritorno della funzione definita non viene affatto utilizzato in prima istanza, facendo scattare un avviso. Ma quando viene assegnato alla variabile $result o lanciato come void, il valore viene considerato consumato.

Gli autori della RFC alla base di questa aggiunta a PHP 8.5 hanno descritto usi più convincenti di questo attributo rispetto al semplice esempio precedente. Uno scenario era quello di una funzione critica con una segnalazione di errore più complessa di un semplice pass/fail, e meglio veicolata attraverso il valore di ritorno della funzione.

Altri miglioramenti relativi agli attributi

Oltre al nuovo attributo #[NoDiscard], gli altri miglioramenti apportati alla funzionalità dei metadati degli attributi nella nuova versione includono:

  • Gli attributi possono ora puntare alle costanti.
  • L’attributo #[Override] può ora essere applicato alle proprietà.
  • L’attributo #[Deprecated] può essere utilizzato su tratti e costanti.
  • Un nuovo attributo #[DelayedTargetValidation] può essere utilizzato per sopprimere gli errori in fase di compilazione degli attributi del nucleo e delle estensioni che vengono utilizzati su obiettivi non validi.

Deprecazioni e rimozioni in PHP 8.5

Ogni versione di PHP contiene un elenco di funzionalità che verranno rimosse nelle versioni future. L’utilizzo di funzionalità deprecate nel codice farà scattare degli avvertimenti. Quando verrano definitivamente rimosse da PHP, il loro utilizzo potrebbe causare errori fatali.

Ecco alcuni importanti elementi deprecati o rimossi in PHP 8.5:

  • L’operatore backtick come alias di shell_exec() è stato deprecato.
  • I nomi di cast non canonici (boolean), (integer), (double) e (binary) sono stati deprecati. Usa invece (bool), (int), (float) e (string).
  • L’impostazione INI disable_classes è stata rimossa perché causava l’interruzione di diversi assunti del motore.
  • La terminazione delle istruzioni di case con un punto e virgola invece che con i due punti è stata deprecata.
  • L’uso di null come offset di un array o quando si chiama array_key_exists() è ora deprecato. Usa invece una stringa vuota.
  • Non è più possibile utilizzare “array” e “callable” come nomi di alias di classe in class_alias().
  • I metodi magici di __sleep() e __wakeup() sono stati deprecati. Al loro posto vanno utilizzati i metodi magici di __serialize() e __unserialize().
  • Ora viene emesso un avviso quando si esegue il casting di NAN in altri tipi.
  • La destrutturazione di valori non-array (diversi da null) utilizzando [] o list() ora emette un avviso.
  • Ora viene emesso un avviso quando si lanciano i float (o le stringhe che sembrano float) in int se non possono essere rappresentati come tali.

Riepilogo

Questo era uno sguardo ai punti salienti della versione 8.5 di PHP. Siamo certi che il nuovo operatore pipe e il miglioramento del parsing degli URI saranno apprezzati dagli sviluppatori. Forse anche le nuove funzioni array_first() e array_last() – anche se avremmo scommesso che esistevano già.

Ma ogni nuova versione di PHP comprende centinaia di cambiamenti. Puoi trovare l’elenco completo degli aggiornamenti di PHP 8.5 nel repository ufficiale del Gruppo PHP su GitHub.

Nel frattempo, qui a Kinsta stiamo lavorando per rendere disponibile PHP 8.5 ai nostri clienti con l’hosting per WordPress. Quando sarà online, potrai passare alla nuova versione utilizzando i nostri strumenti per l’impostazione di PHP.

Steve Bonisteel Kinsta

Steve Bonisteel è un Technical Editor di Kinsta che ha iniziato la sua carriera di scrittore come giornalista della carta stampata, inseguendo ambulanze e camion dei pompieri. Dalla fine degli anni '90 si occupa di tecnologia legata a Internet.