Post Image

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

Nel primo articolo abbiamo visto come prepararci a lavorare con PHP 8.5 partendo da un ambiente di test isolato in Docker e abbiamo analizzato le prime novità più evidenti del linguaggio, come il pipe operator, il supporto esteso a costanti e callable e l’evoluzione del sistema di attributi.

In questa seconda parte entriamo invece in un territorio più vicino al lavoro quotidiano su progetti strutturati: classi, visibilità, debugging, librerie di base e compatibilità. Sono tutti aspetti che, magari, non cambiano il modo in cui scrivi la prima riga di codice, ma che fanno una grande differenza quando il progetto cresce, viene mantenuto nel tempo o condiviso con altri sviluppatori.

PHP 8.5 continua infatti a lavorare su un obiettivo preciso: ridurre il codice superfluo e rendere più esplicite le intenzioni dello sviluppatore. Lo fa migliorando i costrutti orientati agli oggetti, offrendo strumenti di debugging più efficaci e rendendo le API di base più coerenti e meno ambigue.

Vedremo quindi come queste novità si traducono in meno boilerplate, meno errori silenziosi e più controllo, e perché rappresentano un ulteriore passo verso un PHP sempre più maturo e adatto allo sviluppo professionale.

Costrutti e visibilità avanzati

Con PHP 8.5 continuano anche quei miglioramenti meno “appariscenti”, ma fondamentali per chi scrive codice orientato agli oggetti ogni giorno. Parliamo di interventi su visibilità e proprietà, che hanno un obiettivo molto chiaro: ridurre il boilerplate, rendere le classi più espressive e allineare meglio il codice all’intenzione reale dello sviluppatore.

Sono novità di dettaglio, è vero, ma è proprio su questi dettagli che si costruisce un codice più pulito e manutenibile nel tempo.

Asymmetric visibility anche per le proprietà statiche

Il concetto di asymmetric visibility è stato introdotto nelle versioni precedenti di PHP per le proprietà di istanza: la possibilità, cioè, di avere una visibilità diversa in lettura e in scrittura. Un esempio tipico è una proprietà leggibile dall’esterno ma modificabile solo internamente.

Con PHP 8.5, questa possibilità viene estesa anche alle proprietà statiche, rendendo il modello più coerente e completo.

Esempio pratico:

<?php

class Config
{
    public static private(set) string $environment = 'prod';
}

In questo caso:

  • la proprietà environment è leggibile pubblicamente,
  • ma può essere modificata solo dall’interno della classe grazie a private(set).

Tentare di modificarla dall’esterno produrrà un errore:

<?php

echo Config::$environment; // OK

Config::$environment = 'dev'; // ❌ Fatal error: Cannot modify private(set) property

Se invece la modifica avviene dall’interno della classe, è consentita:

<?php

class Config
{
    public static private(set) string $environment = 'prod';

    public static function setEnvironment(string $env): void
    {
        self::$environment = $env; // OK
    }
}

Config::setEnvironment('dev');

echo Config::$environment; // dev

Questo tipo di controllo è estremamente utile per:

  • configurazioni globali,
  • stati condivisi,
  • ambienti applicativi (prod, dev, test),
  • proprietà che devono essere esposte in lettura ma protette da modifiche accidentali.

Prima di queste estensioni, per ottenere lo stesso risultato si ricorreva spesso a getter e setter statici, aumentando il boilerplate e rendendo il codice meno espressivo. Ora l’intenzione è dichiarata direttamente nella proprietà, in modo chiaro e immediato.

Constructor property promotion con proprietà final

Un’altra evoluzione significativa riguarda la constructor property promotion, introdotta in PHP 8.0 per ridurre il boilerplate nella definizione delle classi. Con PHP 8.5, diventa possibile utilizzare la promotion anche su proprietà dichiarate final, permettendo di esprimere in modo più preciso la struttura e le garanzie offerte da un oggetto.

Vediamo un esempio:

<?php

class User
{
    public function __construct(
        public final string $username,
        public final string $email
    ) {}
}

In questo caso, le proprietà username ed email vengono:

  • dichiarate,
  • inizializzate,
  • ed esposte pubblicamente,

direttamente nel costruttore, in modo compatto e leggibile.

L’aggiunta della keyword final introduce una garanzia importante: queste proprietà non possono essere ridefinite da eventuali classi figlie. Questo non riguarda tanto la modifica del valore durante l’esecuzione, quanto la protezione della struttura della classe. Stiamo dichiarando che queste proprietà fanno parte integrante dell’identità dell’oggetto e che la loro presenza e definizione non devono essere alterate tramite ereditarietà.

L’utilizzo è immediato e naturale:

<?php

$user = new User('domenico', 'domenico@email.com');

echo $user->username; // domenico
echo $user->email;    // domenico@email.com

Le proprietà sono leggibili pubblicamente e fanno parte dello stato dell’oggetto fin dalla sua creazione.

Il vantaggio diventa ancora più evidente se confrontiamo questo approccio con quello necessario prima della property promotion. Senza questa funzionalità, lo stesso risultato richiedeva più codice:

<?php

class User
{
    public final string $username;
    public final string $email;

    public function __construct(string $username, string $email)
    {
        $this->username = $username;
        $this->email = $email;
    }
}

Il comportamento è identico, ma la versione con property promotion è più compatta, più leggibile e rende immediatamente chiara la struttura dell’oggetto.

Questo approccio è particolarmente utile in contesti come:

  • DTO (Data Transfer Object), dove l’oggetto rappresenta un insieme di dati strutturati,
  • value object, dove l’identità è definita interamente dalle proprietà,
  • modelli di dominio, dove la stabilità della struttura è essenziale,
  • codice dove è importante evitare modifiche accidentali alla definizione delle classi.

Grazie a queste estensioni, PHP consente di esprimere in modo diretto non solo il comportamento di una classe, ma anche le garanzie strutturali che essa offre, riducendo il boilerplate e migliorando la chiarezza complessiva del codice.

Backtrace per errori fatali e miglior debug

Una delle novità più concrete di PHP 8.5, e probabilmente una delle più apprezzate nella vita reale, riguarda il debugging. A partire da questa versione, gli errori fatali includono di default lo stack trace (backtrace). Può sembrare un dettaglio, ma in pratica cambia moltissimo il modo in cui individui e risolvi un problema.

Fino a oggi, quando PHP incontrava un fatal error, spesso il messaggio si fermava a una riga e a un file. Informazioni utili, certo, ma insufficienti quando l’errore nasceva in una catena di chiamate più profonda, magari passando da servizi, helper, controller o librerie esterne.

Cosa cambia concretamente

Con PHP 8.5, in caso di errore fatale, PHP mostra automaticamente anche il percorso completo delle chiamate che hanno portato a quell’errore. In altre parole, non solo dove il codice si è fermato, ma come ci è arrivato.

Esempio semplice:

<?php

function levelOne() {
    levelTwo();
}

function levelTwo() {
    levelThree();
}

function levelThree() {
    undefinedFunction(); // fatal error
}

levelOne();

Prima di PHP 8.5, il messaggio di errore era spesso limitato a qualcosa del tipo:

Fatal error: Uncaught Error: Call to undefined function undefinedFunction()
in /app/index.php on line 14

Con PHP 8.5, oltre al messaggio, ottieni anche il backtrace completo, che mostra chiaramente:

  • levelOne()
  • levelTwo()
  • levelThree()

Questo significa che non devi più ricostruire mentalmente il flusso, né aggiungere debug_backtrace() o log temporanei solo per capire da dove arriva il problema.

Perché è fondamentale in ambienti reali (anche in produzione)

Nel mondo reale, gli errori fatali raramente nascono in funzioni isolate. Spesso arrivano da:

  • controller che chiamano servizi,
  • servizi che invocano repository,
  • repository che parlano con librerie esterne,
  • codice che gira in contesti asincroni o schedulati.

In questi casi, sapere solo “il file e la riga” non basta. Il backtrace ti dice:

  • quale percorso ha seguito l’esecuzione,
  • quale parte dell’applicazione ha innescato l’errore,
  • se il problema nasce da una chiamata diretta o da un effetto collaterale.

Questo è particolarmente utile anche in produzione, dove:

  • non puoi sempre riprodurre facilmente l’errore,
  • i log sono spesso l’unica fonte di verità,
  • il tempo per capire cosa è successo è critico.

Meno log “di emergenza”, più informazioni utili

Prima di questa novità, era comune vedere codice del genere:

try {
    runJob();
} catch (Throwable $e) {
    error_log($e->getTraceAsString());
    throw $e;
}

Con PHP 8.5, molte di queste soluzioni “di emergenza” diventano meno necessarie, perché il linguaggio stesso fornisce informazioni di debug più complete già al primo errore.

Il risultato è:

  • meno codice di supporto solo per il debug,
  • errori più facili da analizzare,
  • diagnosi più rapide, soprattutto nei team.

Un altro passo verso un PHP più maturo

Questa novità va nella stessa direzione di molte altre introdotte nelle versioni recenti di PHP: rendere gli errori più espliciti e meno silenziosi. Non è solo una questione di comfort per lo sviluppatore, ma di qualità complessiva del software.

Sapere esattamente dove e perché un processo si è fermato riduce:

  • il tempo di debugging,
  • il rischio di fix “alla cieca”,
  • la probabilità che lo stesso bug si ripresenti.

Nel prossimo paragrafo vedremo un altro insieme di miglioramenti meno visibili, ma molto importanti: le novità su estensioni e funzioni di libreria, che impattano direttamente sul codice quotidiano.

Miglioramenti a estensioni e funzioni di libreria

Oltre alle novità più “visibili” sul linguaggio, PHP 8.5 introduce anche una serie di miglioramenti mirati alle estensioni core e alle funzioni di libreria standard. Sono cambiamenti meno appariscenti, ma estremamente importanti per chi lavora con PHP ogni giorno, perché incidono su robustezza, gestione degli errori e qualità del codice.

Sono quelle modifiche che spesso non finiscono nei titoli, ma che nel tempo semplificano davvero lo sviluppo quotidiano.

Nuove opzioni e costanti per cURL

L’estensione cURL è una delle più usate in assoluto in PHP, soprattutto quando si lavora con API esterne, microservizi o integrazioni di terze parti. Con PHP 8.5 arrivano nuove opzioni e costanti, pensate per rendere più esplicito il comportamento delle richieste e migliorare il controllo sugli errori.

Il vantaggio principale è una gestione più chiara degli stati di errore e dei casi limite, riducendo il numero di controlli “manuali” da fare dopo ogni chiamata HTTP.

Un esempio tipico:

<?php

$ch = curl_init('https://api.example.com/data');

curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
]);

$response = curl_exec($ch);

if ($response === false) {
    throw new RuntimeException(curl_error($ch));
}

curl_close($ch);

Con i miglioramenti introdotti, il comportamento di cURL diventa più coerente e prevedibile, soprattutto nei contesti in cui è fondamentale distinguere chiaramente errore di rete, errore applicativo e risposta valida ma inattesa.

DOM, EXIF e altre estensioni: meno ambiguità

PHP 8.5 porta anche miglioramenti incrementali a estensioni molto usate come DOM ed EXIF. In questi casi non parliamo di nuove API rivoluzionarie, ma di:

  • gestione più coerente degli errori,
  • comportamenti meno ambigui,
  • maggiore allineamento con il sistema delle eccezioni.

Ad esempio, lavorare con il DOM HTML/XML diventa più prevedibile quando si incontrano documenti malformati o incompleti, riducendo situazioni in cui il codice “sembra funzionare” ma in realtà produce risultati inattesi.

Questo tipo di miglioramenti è fondamentale perché riduce i bug silenziosi, che sono spesso i più difficili da individuare.

FILTER_THROW_ON_FAILURE: errori come eccezioni

Una delle aggiunte più utili in assoluto è il nuovo flag FILTER_THROW_ON_FAILURE, che permette di gestire gli errori dei filtri come eccezioni, invece che come valori di ritorno ambigui.

Tradizionalmente, funzioni come filter_var() restituiscono false in caso di errore. Questo approccio funziona, ma costringe lo sviluppatore a ricordarsi sempre di controllare il risultato, con il rischio di errori logici se il controllo viene dimenticato.

Esempio classico:

<?php

$email = filter_var($input, FILTER_VALIDATE_EMAIL);

if ($email === false) {
    // errore
}

Con PHP 8.5 puoi scrivere:

<?php

$email = filter_var(
    $input,
    FILTER_VALIDATE_EMAIL,
    FILTER_THROW_ON_FAILURE
);

Se il valore non è valido, PHP lancia direttamente un’eccezione. Il vantaggio è immediato:

  • flusso di controllo più chiaro,
  • meno if sparsi nel codice,
  • integrazione naturale con try/catch.

Questo stile è molto più coerente con il PHP moderno e con le pratiche di sviluppo orientate alla gestione esplicita degli errori.

Piccoli cambiamenti, grande impatto

Nel loro insieme, questi miglioramenti non cambiano il modo in cui scrivi PHP, ma migliorano sensibilmente il modo in cui il codice si comporta quando qualcosa va storto.

  • meno ambiguità nei valori di ritorno,
  • più eccezioni al posto di errori silenziosi,
  • API più coerenti tra loro.

È un ulteriore passo verso un PHP che aiuta lo sviluppatore a scrivere codice corretto, invece di limitarsi a eseguire istruzioni.

Nel prossimo e ultimo paragrafo tireremo le somme, per capire perché PHP 8.5 rappresenta un aggiornamento consigliato e come affrontare il passaggio in modo consapevole.

Deprecazioni e modifiche da conoscere

Come ogni nuova versione di PHP, anche PHP 8.5 porta con sé alcune deprecazioni e piccoli aggiustamenti che è importante conoscere prima di aggiornare un progetto esistente. Nulla di traumatico o improvviso, ma una serie di segnali chiari che indicano la direzione futura del linguaggio.

È bene chiarirlo subito: PHP 8.5 è altamente compatibile con PHP 8.4. La stragrande maggioranza del codice continuerà a funzionare senza modifiche. Tuttavia, ignorare le deprecazioni significa rimandare un problema che prima o poi tornerà, spesso nel momento meno opportuno.

Cosa significa “deprecato” in PHP

Quando una funzionalità viene marcata come deprecated, non viene rimossa immediatamente. PHP continua a supportarla, ma segnala che:

  • non dovrebbe più essere usata in nuovo codice,
  • potrebbe essere rimossa in una versione futura,
  • conviene iniziare a migrare verso l’alternativa consigliata.

In fase di sviluppo, queste deprecazioni si manifestano spesso come warning, che molti team scelgono (giustamente) di trattare con attenzione.

Perché queste modifiche richiedono attenzione

Le deprecazioni introdotte o confermate in PHP 8.5 vanno nella stessa direzione vista nelle versioni precedenti:

  • API più coerenti,
  • comportamenti meno ambigui,
  • riduzione di casi “magici” o impliciti.

Questo significa che alcune abitudini storiche, magari innocue, vengono progressivamente scoraggiate. Non perché “sbagliate”, ma perché nel tempo hanno dimostrato di essere fonte di bug, incomprensioni o codice difficile da mantenere.

Il rischio non è tanto che il codice “smetta di funzionare”, quanto che:

  • i warning vengano ignorati,
  • il debito tecnico aumenti,
  • l’aggiornamento alla versione successiva diventi più costoso.

Un esempio tipico: warning oggi, errore domani

Molte deprecazioni seguono questo schema:

  1. oggi: warning di deprecazione,
  2. domani: comportamento rimosso o modificato.

Questo dà agli sviluppatori tempo per adattarsi, ma solo se i warning vengono presi sul serio. Ecco perché, durante l’aggiornamento a PHP 8.5, è una buona pratica:

  • attivare un livello di error reporting elevato in ambiente di test,
  • analizzare i warning,
  • correggere gradualmente le parti di codice interessate.

Come affrontare l’aggiornamento in modo consapevole

Il modo migliore per gestire queste modifiche non è evitarle, ma anticiparle. In pratica:

  • aggiorna PHP 8.5 prima in staging o sviluppo,
  • esegui test automatici e manuali,
  • verifica la presenza di warning di deprecazione,
  • aggiorna librerie e dipendenze che potrebbero non essere ancora allineate.

Questo approccio riduce drasticamente il rischio e ti permette di arrivare preparato alle versioni future di PHP, senza aggiornamenti “forzati” dell’ultimo minuto.

Un linguaggio che evolve con gradualità

Le deprecazioni di PHP 8.5 confermano una tendenza ormai chiara: PHP evolve in modo incrementale, comunicando per tempo cosa cambierà e perché. Per chi sviluppa professionalmente, questo è un enorme vantaggio.

Ignorare questi segnali significa accumulare debito tecnico. Ascoltarli, invece, permette di mantenere il codice pulito, moderno e allineato al futuro del linguaggio.

Nel prossimo paragrafo tireremo le conclusioni, per capire perché PHP 8.5 rappresenta un aggiornamento consigliato e come queste novità si traducono in benefici concreti nel lavoro quotidiano.

Conclusione

Guardando l’insieme delle novità introdotte, PHP 8.5 si conferma come un miglioramento concreto per la produttività degli sviluppatori, più che come un semplice aggiornamento di routine. Non stravolge il linguaggio, ma lo rende più leggibile, più esplicito e più sicuro, soprattutto nel lavoro quotidiano su progetti reali.

Il pipe operator aiuta a scrivere codice più lineare e comprensibile. Il supporto esteso a costanti, closure e callable riduce il boilerplate e migliora l’organizzazione del codice. Gli attributi avanzati come NoDiscard spingono verso uno stile più corretto e intenzionale, mentre il backtrace sugli errori fatali rappresenta un enorme passo avanti nel debugging, anche in contesti complessi e in produzione. A tutto questo si aggiunge una API di libreria più coerente, con una gestione degli errori sempre più orientata alle eccezioni e meno ai valori ambigui.

In altre parole, PHP 8.5 non fa “più cose”, ma fa meglio le stesse cose, aiutando lo sviluppatore a evitare errori silenziosi e a mantenere il codice pulito nel tempo. È il segno di un linguaggio che ha ormai imboccato con decisione una strada di maturità.

Come sempre, il consiglio è di non aggiornare mai direttamente in produzione. Il percorso corretto passa da un ambiente di staging o sviluppo, dove testare il codice, intercettare eventuali warning di deprecazione e verificare la compatibilità delle dipendenze. Questo approccio riduce i rischi e permette di adottare le novità in modo consapevole.

Per chi vuole approfondire ogni singola feature, la documentazione ufficiale e risorse come PHP.Watch restano punti di riferimento fondamentali per seguire l’evoluzione del linguaggio e capire non solo cosa cambia, ma perché cambia.

In definitiva, aggiornare a PHP 8.5 significa investire nella qualità del proprio codice, oggi e nel futuro. Una scelta che premia chi sviluppa, chi mantiene e chi, domani, dovrà mettere mano a quel codice, soprattutto se affrontata con consapevolezza e testata passo dopo passo, come abbiamo visto in questa serie di articoli.