Post Image

PHP 8.5: novità e miglioramenti spiegati con esempi pratici (Parte 1)

Con il rilascio di PHP 8.5, il linguaggio compie un ulteriore passo avanti nel suo percorso di evoluzione. Non parliamo di una rivoluzione improvvisa, ma di una minor release pensata per raffinare l’esperienza di sviluppo, rendere il codice più leggibile e fornire strumenti più solidi per il lavoro quotidiano di chi usa PHP ogni giorno, sia su piccoli progetti che su applicazioni complesse.

Negli ultimi anni PHP ha cambiato passo in modo evidente. A partire da PHP 8.0, passando per PHP 8.1, PHP 8.2, fino ad arrivare a PHP 8.4, ogni versione ha introdotto miglioramenti concreti: tipizzazione più rigorosa, oggetti più espressivi, meno ambiguità e una crescente attenzione alla qualità del codice. PHP 8.5 si inserisce perfettamente in questa roadmap, continuando a lavorare sugli stessi obiettivi: chiarezza, sicurezza e produttività.

Questa nuova versione non stravolge il modo di scrivere codice, ma introduce nuove funzionalità mirate, spesso richieste da tempo dalla community, che permettono di scrivere PHP in modo più lineare e moderno. L’idea di fondo è semplice: meno codice cerimoniale, meno errori nascosti e più leggibilità, soprattutto quando il progetto cresce e il codice viene letto, mantenuto e condiviso nel tempo.

È importante però chiarire subito un punto: aggiornare PHP non significa solo “avere l’ultima versione”, ma mettersi nelle condizioni di sperimentare e capire davvero cosa cambia. Per questo motivo, prima di entrare nel dettaglio delle singole novità, è fondamentale disporre di un ambiente di test sicuro e isolato.

Anche un controllo banale della versione in uso aiuta a inquadrare il contesto:

<?php echo PHP_VERSION;

Nel resto dell’articolo vedremo cosa cambia davvero in PHP 8.5, con esempi pratici e spiegazioni semplici. Ma prima di farlo, prepareremo un ambiente Docker con PHP 8.5, che useremo per provare direttamente tutte le funzionalità descritte, passo dopo passo. In questo modo non ci limiteremo a raccontare le novità, ma le metteremo subito alla prova, nel modo più concreto possibile.

Preparare l’ambiente di test: PHP 8.5 in Docker

Prima di entrare nel dettaglio delle novità di PHP 8.5, è utile fermarsi un attimo e creare un ambiente di prova isolato, dove sperimentare il codice in sicurezza. Il modo più semplice e pulito per farlo è usare Docker, evitando installazioni locali, conflitti di versione o modifiche al sistema.

L’obiettivo è chiaro: avere una shell con PHP 8.5 pronto all’uso, scrivere codice con vi e lanciare subito gli esempi che vedremo nei paragrafi successivi.

Avviare un container PHP 8.5

Assumendo di avere Docker installato, possiamo partire direttamente da un’immagine ufficiale PHP. Per lavorare comodamente da riga di comando, usiamo la variante CLI.

docker run -it --rm php:8.5-cli bash

Cosa fa questo comando:

  • scarica (se necessario) l’immagine php:8.5-cli,
  • avvia un container interattivo,
  • apre una shell bash,
  • elimina il container alla chiusura (--rm).

Una volta dentro, possiamo verificare subito la versione:

php -v

Dovresti vedere chiaramente PHP 8.5.x, segno che l’ambiente è pronto.

Usare vi come editor

L’immagine CLI di PHP è minimale, ma vi è già disponibile, ed è più che sufficiente per fare prove rapide.

Creiamo un file di test:

vi test.php

Inseriamo un contenuto minimale:

<?php

echo "PHP 8.5 pronto!\n";

Salviamo ed eseguiamo:

php test.php

Da questo momento in poi, tutti gli esempi dell’articolo possono essere provati direttamente qui, uno alla volta, senza uscire dal container.

(Opzionale) Montare una directory locale

Se preferisci lavorare su file persistenti, puoi montare una directory del tuo host dentro il container. Ad esempio:

docker run -it --rm \
  -v $(pwd):/app \
  -w /app \
  php:8.5-cli bash

In questo modo:

  • i file restano sul tuo filesystem,
  • puoi versionarli,
  • puoi riavviare il container senza perdere nulla.

Anche in questo caso, vi rimane l’editor principale, semplice e immediato.

Perché partire da Docker

Questo approccio ha diversi vantaggi:

  • nessuna installazione locale di PHP,
  • nessun rischio per l’ambiente di produzione,
  • possibilità di provare subito le nuove feature di PHP 8.5,
  • massima coerenza tra esempi e risultati.

È esattamente il tipo di setup ideale per sperimentare il pipe operator, gli attributi, le nuove costanti e il debugging, che vedremo nei prossimi paragrafi.

Da qui in avanti, tutti gli esempi di codice dell’articolo possono essere copiati, modificati e lanciati direttamente in questo ambiente di test, rendendo l’aggiornamento a PHP 8.5 non solo teorico, ma immediatamente pratico.

Il nuovo operatore Pipe (|>)

Tra le novità più interessanti di PHP 8.5 c’è senza dubbio il pipe operator (|>): un operatore che ti permette di scrivere trasformazioni e passaggi “a catena” in modo più leggibile, perché l’esecuzione scorre da sinistra verso destra, senza costringerti a ragionare “al contrario” come spesso succede con le chiamate annidate.

L’idea è semplice: prendi un valore, lo passi a una funzione, prendi il risultato e lo passi alla funzione successiva… e così via. In termini tecnici, |> prende l’espressione a sinistra e la passa come unico argomento al callable a destra, restituendo il risultato di quel callable.

Pipe operator in PHP 8.5: perché migliora la leggibilità

Il vantaggio non è “fare cose nuove” (con PHP potevi già ottenere lo stesso risultato), ma farle con un codice che si legge meglio e che tende a diventare più chiaro man mano che la catena cresce.

Pensa al caso tipico: prima di PHP 8.5 ti capitava spesso di scrivere funzioni annidate, tipo “dentro e fuori”:

<?php

$title = "  PHP 8.5 Released  ";

$result = strtoupper(trim($title));
// oppure, con annidamento:
$result2 = strtoupper(trim($title));

echo $result . PHP_EOL;

Con catene più lunghe, l’annidamento diventa presto difficile da leggere:

<?php

$input = "  Hello World  ";

// lettura “inside-out”
$out = strlen(strtolower(trim($input)));

echo $out . PHP_EOL;

Con il pipe operator, invece, puoi scrivere la stessa logica in modo lineare:

<?php

$input = "  Hello World  ";

// lettura left-to-right
$out = $input
    |> trim(...)
    |> strtolower(...)
    |> strlen(...);

echo $out . PHP_EOL;

Questo è esattamente il tipo di scenario per cui |> è stato introdotto: sostituire chiamate annidate con una sequenza leggibile.

PHP 8.5 e sanitizzazione degli input: un esempio reale

Un caso comune nello sviluppo PHP è “normalizzare” una stringa: togli spazi, uniforma maiuscole/minuscole, gestisci caratteri particolari, ecc.

Versione “classica” (con variabili intermedie):

<?php

$raw = "  Peppino ";

$normalized = trim($raw);
$normalized = strtolower($normalized);

echo $normalized; // "peppino"

Versione con pipe operator (più compatta e leggibile):

<?php

$raw = "  Peppino  ";

$normalized = $raw
    |> trim(...)
    |> strtolower(...);

echo $normalized; // "peppino"

Qui il guadagno non è solo estetico: quando leggi il codice dopo mesi (o lo legge un collega), il flusso è immediato: prendo $raw, faccio trim, poi lowercase.

Pipe + funzioni che richiedono più parametri: come si fa?

Il pipe passa un solo valore al callable a destra. Se la funzione che vuoi usare richiede più argomenti, la strategia più semplice è usare una closure (o una arrow function) che “chiude” gli altri parametri.

Esempio: voglio fare str_replace(' ', '-', $value).

<?php

$slug = "PHP 8.5 pipe operator";

$slug = $slug
    |> trim(...)
    |> strtolower(...)
    |> (fn($s) => str_replace(' ', '-', $s));

echo $slug; // "php-8.5-pipe-operator"

È un approccio pulito, perché la chain rimane leggibile e tu controlli chiaramente il passaggio. (Ed è esattamente uno dei pattern discussi quando si parla dell’ergonomia di |>.)

Quando usarlo (e quando no)

Il pipe operator dà il meglio quando stai facendo una sequenza di trasformazioni “una dopo l’altra”, soprattutto su stringhe, array (con helper o librerie), validazioni o normalizzazioni. È una feature che punta a rendere PHP più espressivo e moderno, senza cambiare la natura del linguaggio.

Se invece hai una logica complessa con molti rami (if/else), side-effect (scritture su DB, I/O, logica “procedurale”) o funzioni che non si prestano a un passaggio monovalore, spesso è meglio restare su variabili esplicite: a volte la chiarezza vince sulla compattezza.

Supporto esteso a costanti e chiamate inline

Un’altra novità molto interessante di PHP 8.5, forse meno “appariscente” del pipe operator ma estremamente rilevante nella pratica, riguarda il potenziamento delle espressioni costanti. In particolare, PHP compie un passo importante nel rendere costanti e callable più espressivi, riducendo ulteriormente il codice ripetitivo e migliorando l’organizzazione delle configurazioni.

Storicamente, in PHP le costanti sono sempre state piuttosto limitate: potevano contenere valori semplici (stringhe, numeri, array), ma non tutto ciò che oggi consideriamo naturale in un linguaggio moderno. Con PHP 8.5 questa rigidità viene ulteriormente allentata.

Closure e first-class callables nelle espressioni costanti

Con PHP 8.5 diventa possibile usare first-class callable anche all’interno delle espressioni costanti. Questo significa che ora puoi definire riferimenti a funzioni e metodi come valori costanti, cosa che prima richiedeva workaround o codice aggiuntivo.

Facciamo un esempio semplice. Prima di PHP 8.5, una cosa del genere non era ammessa in una costante:

<?php

const NORMALIZE = trim(...); // ❌ non consentito prima

Con PHP 8.5, invece, questo diventa valido:

<?php

const NORMALIZE = trim(...);

echo (NORMALIZE)("  PHP 8.5  "); // PHP 8.5

Qui trim(...) è un first-class callable, cioè un riferimento alla funzione trim che può essere passato, memorizzato e richiamato. Il vantaggio è evidente: puoi definire comportamenti riutilizzabili come costanti, senza dover ricorrere a classi di servizio o funzioni globali sparse nel codice.

Questo approccio è particolarmente utile quando lavori con configurazioni, pipeline di trasformazioni, o mapping funzionali, dove prima eri costretto a mescolare costanti e logica.

Costanti con attributi: più contesto, meno ambiguità

Un’altra estensione importante riguarda la possibilità di usare attributi anche sulle costanti in modo più flessibile. Gli attributi, introdotti in PHP 8.0, sono diventati uno strumento fondamentale per aggiungere metadati strutturati al codice.

Con PHP 8.5, le costanti annotate con attributi diventano ancora più utili in contesti come:

  • configurazioni applicative,
  • mapping automatici,
  • validazioni,
  • framework e librerie che fanno uso di reflection.

Esempio:

<?php

#[Deprecated(reason: "Usare NEW_TIMEOUT")]
const OLD_TIMEOUT = 30;

const NEW_TIMEOUT = 20;

In questo caso la costante non è solo un valore, ma porta con sé informazioni semantiche che possono essere lette da strumenti automatici, IDE o framework. Questo aiuta a rendere il codice più auto-documentato e meno soggetto a utilizzi impropri nel tempo.

In sintesi, il supporto esteso a first-class callable e costanti con attributi va nella direzione di un PHP sempre più espressivo, dichiarativo e pulito. È una di quelle novità che magari non “fanno notizia”, ma che nel tempo migliorano sensibilmente la qualità del codice e la sua manutenibilità.

Nel prossimo paragrafo vedremo come questa filosofia prosegue anche nel sistema di attributi avanzati, con strumenti pensati per prevenire errori e rendere il codice più sicuro già in fase di sviluppo.

Attributi migliorati: NoDiscard e DelayedTargetValidation

Con PHP 8.5 il sistema degli attributi continua a maturare e a spostarsi sempre di più verso un obiettivo chiaro: aiutare lo sviluppatore a prevenire errori, non solo a correggerli dopo. Le due novità principali in questo ambito sono l’introduzione dell’attributo #[\NoDiscard] e il nuovo meccanismo di #[\DelayedTargetValidation].

Non si tratta di funzionalità “rumorose”, ma di strumenti molto concreti che migliorano la qualità del codice nel tempo, soprattutto nei progetti medi e grandi.

#[\NoDiscard]: quando ignorare un valore è un errore

Quante volte capita di chiamare una funzione che restituisce un valore importante… e poi dimenticarsi di usarlo? In PHP questo è sempre stato possibile, anche quando il valore restituito rappresentava l’esito di un’operazione critica.

Con PHP 8.5 puoi dichiarare esplicitamente che il valore di ritorno di una funzione non deve essere ignorato, usando l’attributo #[\NoDiscard].

Esempio semplice:

<?php

#[\NoDiscard]
function generateToken(): string
{
    return bin2hex(random_bytes(16));
}

Se qualcuno usa la funzione in questo modo:

<?php

generateToken(); // valore ignorato

PHP segnalerà il problema (warning), evidenziando che il valore di ritorno è stato scartato. Il messaggio non serve a “rompere” il codice, ma a far emergere un possibile bug logico.

Questo è particolarmente utile per:

  • funzioni di validazione,
  • metodi che restituiscono oggetti immutabili,
  • operazioni che producono nuovi stati (token, hash, configurazioni),
  • API che seguono uno stile funzionale.

In pratica, #[\NoDiscard] rende esplicita un’intenzione che prima era solo implicita: questa funzione ha senso solo se usi il risultato.

Un esempio realistico: validazione

<?php

#[\NoDiscard]
function validateEmail(string $email): bool
{
    return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
}

validateEmail("test@example.com"); // ⚠️ valore ignorato

Qui il problema è evidente: chiamare una funzione di validazione senza usare il risultato non ha alcun senso. Con #[\NoDiscard], PHP ti aiuta a intercettare questo tipo di errore già in fase di sviluppo.

#[\DelayedTargetValidation]: errori più intelligenti sugli attributi

La seconda novità riguarda un aspetto più avanzato, ma molto importante per chi lavora con framework, librerie e reflection: #[\DelayedTargetValidation].

Normalmente, PHP valida immediatamente se un attributo è applicato a un target valido (classe, metodo, proprietà, costante, ecc.). In alcuni scenari complessi, però, questa validazione immediata può essere un problema, soprattutto quando:

  • gli attributi vengono analizzati dinamicamente,
  • il codice è caricato in più fasi,
  • il controllo del target avviene a runtime tramite reflection.

Con #[\DelayedTargetValidation], la validazione del target viene rimandata, consentendo a librerie e framework di gestire questi casi in modo più flessibile.

Esempio concettuale:

<?php

#[\Attribute]
#[\DelayedTargetValidation]
class Route
{
    public function __construct(public string $path) {}
}

In questo modo, PHP non genera subito un errore se l’attributo viene applicato in un contesto che verrà validato successivamente. È una funzionalità pensata per autori di framework e sistemi avanzati, ma che migliora indirettamente l’esperienza di tutti.

Meno errori latenti, più codice corretto

Il filo conduttore di queste novità è chiaro: spostare gli errori il più possibile “a sinistra”, cioè verso la fase di scrittura del codice, invece che scoprirli in produzione.

  • #[\NoDiscard] aiuta a evitare bug logici silenziosi.
  • #[\DelayedTargetValidation] rende il sistema degli attributi più robusto e adatto a casi reali complessi.

Nel loro insieme, questi miglioramenti rendono PHP 8.5 un linguaggio più esplicito, più sicuro e più attento alle intenzioni dello sviluppatore. Non cambiano il modo in cui scrivi codice ogni giorno, ma alzano il livello di qualità medio del software che produci.

Conclusione

In questa prima parte abbiamo visto come PHP 8.5 continui il percorso di maturazione del linguaggio, non con cambiamenti radicali, ma con miglioramenti mirati e concreti. Abbiamo preparato un ambiente di test pulito e isolato con Docker, proprio per poter toccare con mano le novità, e ci siamo concentrati sulle prime feature che incidono direttamente sul modo di scrivere codice ogni giorno.

Il pipe operator, il supporto esteso a costanti e callable, e l’evoluzione del sistema di attributi mostrano chiaramente una direzione: PHP diventa sempre più espressivo, intenzionale e attento alla qualità del codice, riducendo il boilerplate e aiutando lo sviluppatore a prevenire errori prima che diventino problemi reali.

Ma questo è solo l’inizio. PHP 8.5 introduce anche altri miglioramenti importanti che meritano uno spazio dedicato: dalla visibilità avanzata delle proprietà, al debugging più efficace grazie ai backtrace sugli errori fatali, fino ai cambiamenti nelle estensioni di libreria e alle deprecazioni da conoscere per aggiornare i progetti in modo consapevole.

Nella seconda parte dell’articolo entreremo proprio in questi aspetti, per completare il quadro e capire perché PHP 8.5 non è solo una nuova versione, ma un passo ulteriore verso un linguaggio più solido e moderno, pensato per il lavoro reale.