f in x
Readonly Properties e Classi Readonly in PHP 8: Immutabilità Pratica per Codice più Sicuro
> cd .. / HUB_EDITORIALE > Visualizza in Inglese
Sviluppo di siti web

Readonly Properties e Classi Readonly in PHP 8: Immutabilità Pratica per Codice più Sicuro

[2026-06-10] Author: Ing. Calogero Bono

Hai mai passato ore a rincorrere un bug perché una proprietà di un oggetto è stata modificata da un metodo che non doveva toccarla? Succede a tutti. Soprattutto quando lavori con DTO, modelli di dominio o configurazioni che dovrebbero restare fisse dopo l'inizializzazione. PHP 8.1 ha introdotto le proprietà readonly, e PHP 8.2 ha fatto un passo avanti con le classi readonly. Non sono funzionalità di contorno: cambiano il modo in cui scrivi codice, riducono gli effetti collaterali e rendono i tuoi oggetti prevedibili. Noi, di Meteora Web, le usiamo quotidianamente nei progetti Laravel e nelle nostre piattaforme proprietarie. In questa guida ti mostriamo come usarle per davvero, non solo a parole.

Perché l'immutabilità conta anche in PHP

PHP è storicamente un linguaggio dinamico e permissivo. Puoi modificare una proprietà pubblica da qualsiasi parte del codice. Questo è comodo per scrivere veloce, ma è un disastro quando il progetto cresce. Un oggetto che rappresenta un ordine o un utente non dovrebbe cambiare dopo essere stato creato, a meno che non sia esplicitamente previsto.

L'immutabilità ti dà garanzie: una volta che un valore è stato impostato, nessun metodo, nessuna funzione, nessun framework può alterarlo per sbaglio. Il risultato? Meno bug, codice più facile da testare, comportamento deterministico. E non serve un pattern complesso: PHP ti dà gli strumenti a livello di linguaggio.

Sponsored Protocol

Readonly Properties: Come funzionano (e cosa non fanno)

Le proprietà readonly sono state introdotte in PHP 8.1. La sintassi è semplice: basta anteporre readonly alla dichiarazione. Il vincolo è che la proprietà può essere inizializzata solo una volta — tipicamente nel costruttore o direttamente nella dichiarazione (se è una costante di classe non statica). Dopo non può più essere modificata.

class UserDTO {
    public readonly string $name;
    public readonly string $email;

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

$user = new UserDTO('Mario Rossi', 'mario@example.com');
echo $user->name; // Mario Rossi
$user->name = 'Luca'; // Errore: Cannot modify readonly property

Cose da sapere:

  • Le proprietà readonly devono avere un tipo dichiarato (type hint). Non puoi scrivere public readonly $name; senza tipo.
  • Non possono essere static. Le readonly sono per istanze.
  • Il valore può essere un oggetto mutabile. La proprietà readonly impedisce di cambiare il riferimento, ma non impedisce di modificare l'oggetto stesso se è mutabile. Esempio: public readonly array $items; — puoi fare $user->items[] = 'new';? No, perché [] = modifica l'array, ma l'array è un tipo valore in PHP? In realtà, $user->items[] = 'new' tenta di modificare la proprietà readonly — errore. Ma se l'array è un oggetto come Collection, puoi chiamare metodi che lo modificano. Quindi attenzione: readonly protegge il riferimento, non il contenuto.

Errore comune: provare a inizializzare una proprietà readonly in un metodo diverso dal costruttore o al di fuori della dichiarazione. Non funziona. L'unico momento in cui puoi assegnare è nella dichiarazione stessa (con valore costante) o nel costruttore.

Sponsored Protocol

Readonly properties in classi con costruttori promossi

La combinazione più usata: dichiarare le proprietà readonly direttamente nel costruttore. PHP 8 permette di unire dichiarazione e assegnazione. È pulito e compatto.

class ProductDTO {
    public function __construct(
        public readonly string $sku,
        public readonly float $price
    ) {}
}

Con una riga hai tutto: costruttore, proprietà, tipo, immutabilità. Meno boilerplate, più leggibilità.

Classi Readonly in PHP 8.2: immutabilità di livello superiore

PHP 8.2 ha introdotto le classi readonly. Aggiungi readonly prima di class e automaticamente tutte le proprietà diventano readonly. In più, non puoi aggiungere proprietà non readonly. Il costruttore promosso (o esplicito) con readonly è implicito.

readonly class OrderDTO {
    public function __construct(
        public string $orderId,
        public float $total
    ) {}
}

// Equivale a scrivere ogni proprietà come readonly
// Non puoi dichiarare proprietà normali in questa classe

Vantaggi pratici:

Sponsored Protocol

  • Zero ripetizioni: non devi scrivere readonly su ogni proprietà.
  • Intenzione chiara: chi legge capisce subito che la classe è immutabile.
  • Il compilatore (opcache) può ottimizzare meglio, ma il guadagno è marginale nella pratica.

Attenzione: una classe readonly non può estendere una classe non readonly, e viceversa. L'ereditarietà è permessa solo tra classi readonly. Inoltre, le proprietà di una classe readonly non possono essere static.

Immutabilità pratica: esempi reali dal nostro lavoro

Noi usiamo le classi readonly per modellare DTO, comandi CQRS, eventi di dominio e risposte API. Un caso concreto: in una piattaforma di gestione ordini che abbiamo sviluppato per un cliente, ogni ordine viene rappresentato con una classe OrderSnapshot che viene passata tra i servizi. Grazie a readonly, siamo certi che nessun servizio modifichi i dati dell'ordine dopo la creazione. Se un servizio deve aggiornare lo stato, restituisce una nuova istanza. Questo rende il flusso prevedibile.

readonly class OrderSnapshot {
    public function __construct(
        public int $id,
        public string $status,
        public float $total,
        public array $items
    ) {}

    // Factory method per creare una nuova istanza con stato cambiato
    public function withStatus(string $newStatus): self {
        return new self(
            id: $this->id,
            status: $newStatus,
            total: $this->total,
            items: $this->items
        );
    }
}

In questo modo, lo stato originale non viene mai perso, e puoi tracciare le modifiche confrontando le istanze.

Sponsored Protocol

Serializzazione e readonly: cosa cambia

Le proprietà readonly possono essere serializzate con serialize() e json_encode() normalmente. Tuttavia, quando deserializzi con unserialize() o ReflectionProperty::setValue(), PHP non rispetta il vincolo readonly: può assegnare il valore anche a una proprietà readonly. Questo è un comportamento noto e voluto per consentire la deserializzazione. Se vuoi una protezione rigorosa anche in fase di deserializzazione, devi gestirla manualmente (ad esempio, rendendo le proprietà private e fornendo un factory method).

Reflection e readonly: limiti da conoscere

Con ReflectionProperty puoi modificare una proprietà readonly chiamando setValue(). Funziona, ma è considerato un uso avanzato per librerie di ORM o serializzatori. Se stai scrivendo codice normale, non dovresti mai fare affidamento su questo. Le readonly sono un contratto per lo sviluppatore, non una barriera di sicurezza.

Quando usare readonly e quando no

Usa readonly:

  • DTO (Data Transfer Object) che trasportano dati tra layer
  • Eventi di dominio
  • Comandi CQRS
  • Configurazioni immutabili (ad esempio, parametri di connessione, impostazioni di sistema)
  • Oggetti valore (Value Object)

Non usare readonly:

Sponsored Protocol

  • Entità Doctrine o Eloquent che devono essere modificate dall'ORM (a meno che non usi event sourcing o snapshot)
  • Oggetti che per natura cambiano frequentemente (es. una sessione utente, uno stato transitorio)
  • Classi con dipendenze di servizi iniettate via costruttore (non è sbagliato, ma spesso non serve se il servizio è immutabile)

In sintesi — cosa fare adesso

  1. Identifica i DTO nei tuoi progetti. Ogni classe che serve solo per trasportare dati tra controller e servizio, o tra servizi, è candidata perfetta per readonly.
  2. Riscrivi le prime tre classi DTO con readonly class o con proprietà readonly. Usa i costruttori promossi per ridurre la verbosità.
  3. Aggiungi un'eccezione di tipo se una proprietà readonly viene modificata — in realtà PHP lo fa per te, ma puoi documentare perché.
  4. Confronta il codice prima e dopo. Noterai che il costruttore diventa l'unico punto di scrittura, e il resto è sola lettura. Questo riduce il carico mentale.
  5. Aggiorna le tue code review: quando vedi una proprietà pubblica mutabile in una classe che sembra un DTO, chiedi se può essere readonly.

L'immutabilità non è una moda: è una disciplina che paga nel lungo periodo. PHP 8 te la mette a disposizione con una sintassi pulita. Noi, di Meteora Web, abbiamo iniziato a usarla su tutti i nuovi progetti e non torniamo indietro. Prova anche tu.

Ing. Calogero Bono

> AUTHOR_EXTRACTED

Ing. Calogero Bono

Ingegnere Informatico, co-fondatore di Meteora Web. Esperto in architetture software, sicurezza informatica e sviluppo sistemi scalabili.
[ Read Full Dossier ]

> METEORA_WEB // WEB AGENCY

Costruiamo la presenza digitale che la tua azienda merita.

Siti web, social, pubblicità online, e-commerce e hosting performante: ingegnerizzati con metodo da ingegneri informatici a Sciacca, per tutta Italia.

> MW_JOURNAL

> READ_ALL()