f in x
Readonly Properties, Enums e Match Expression in PHP 8: Una Guida Completa alle Feature che Trasformano il Codice Moderno
> cd .. / HUB_EDITORIALE > Visualizza in Inglese
Analisi dei dati e metriche

Readonly Properties, Enums e Match Expression in PHP 8: Una Guida Completa alle Feature che Trasformano il Codice Moderno

[2026-05-29] Author: Ing. Calogero Bono

Le versioni moderne di PHP hanno introdotto strumenti che modificano profondamente il modo di progettare e scrivere codice. Tra questi, readonly properties, enums e match expression rappresentano tre pilastri fondamentali per un codice più espressivo, sicuro e manutenibile. Questa guida esplora ciascuna feature in dettaglio, mostrando esempi reali, casi d'uso avanzati e come combinarle per creare applicazioni robuste.

Readonly Properties: Immutabilità Dichiarativa

Introdotte in PHP 8.1, le proprietà readonly consentono di dichiarare che una proprietà di una classe può essere assegnata una sola volta, tipicamente nel costruttore. Dopo l'inizializzazione, qualsiasi tentativo di modifica solleva un'eccezione Error. Questo meccanismo rafforza l'immutabilità a livello di singola proprietà, senza dover scrivere getter manuali o logiche di blocco.

Sintassi e Comportamento

class User {
    public readonly string $name;
    public readonly int $age;

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

$user = new User('Alice', 30);
// $user->name = 'Bob'; // Error: Cannot modify readonly property User::$name

Le readonly property possono essere dichiarate con tipo (inclusi union e intersection types) e possono essere type-promoted nel costruttore, rendendo il codice ancora più conciso:

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

Non è consentito dichiarare una proprietà readonly senza tipo, né utilizzare static o abstract su di essa. Inoltre, non è possibile definire un valore di default che non sia una costante; la proprietà deve essere inizializzata nel costruttore o tramite una chiamata al costruttore stesso.

Vantaggi e Casi d'Uso

Le readonly property sono ideali per Value Object, DTO (Data Transfer Object), configurazioni immutabili e qualsiasi entità che non debba cambiare dopo la creazione. Eliminano la necessità di getter (se non si vuole incapsulamento aggiuntivo) e prevengono errori dovuti a modifiche accidentali. Insieme agli enums e alla match expression, permettono di scrivere codice dichiarativo e prevedibile.

Enums: Un Tipo di Dati Discreto e Sicuro

Gli enum sono stati introdotti in PHP 8.1 come un vero e proprio tipo di dato. Permettono di definire un insieme finito di valori possibili, migliorando la leggibilità e la sicurezza del codice rispetto all'uso di costanti o interi arbitrari.

Enum Puri e Backed Enum

Un enum puro non ha un valore associato:

enum Status {
    case Pending;
    case Approved;
    case Rejected;
}

Un backed enum associa a ogni caso un valore scalare (int o string):

enum OrderStatus: string {
    case New = 'new';
    case Processing = 'processing';
    case Shipped = 'shipped';
    case Delivered = 'delivered';
    case Cancelled = 'cancelled';
}

Gli enums possono implementare interfacce, avere metodi propri (anche statici) e supportare il pattern matching attraverso la match expression o il nuovo enum con match.

Metodi e Interfacce negli Enums

enum Color: int {
    case Red = 1;
    case Green = 2;
    case Blue = 3;

    public function hexCode(): string {
        return match($this) {
            Color::Red => '#FF0000',
            Color::Green => '#00FF00',
            Color::Blue => '#0000FF',
        };
    }
}

Questa integrazione rende gli enums molto più potenti delle semplici costanti: ogni caso è un oggetto con comportamento.

Match Expression: Switch Migliorato e Espressivo

Introdotta in PHP 8.0, la match expression è un costrutto che unisce le capacità di switch con la sicurezza di un confronto stretto (===) e la possibilità di restituire un valore. A differenza dello switch, la match expression è un'espressione che può essere assegnata.

Sintassi Fondamentale

$result = match($value) {
    1 => 'Uno',
    2, 3 => 'Due o tre',
    default => 'Altro',
};

Ogni braccio è separato da una virgola. Non c'è break; il primo braccio corrispondente viene eseguito e la sua espressione restituita. Se nessun braccio corrisponde e non esiste un default, viene lanciata un'eccezione UnhandledMatchError.

Vantaggi rispetto a Switch

  • Confronto stretto (===) invece di ==, prevenendo errori di tipo.
  • Restituisce un valore, permettendo codice più conciso e funzionale.
  • Supporta pattern multipli (es. 2, 3 => ...).
  • Nessun fall-through: ogni braccio è autonomo.

La match expression è particolarmente potente quando combinata con enums e readonly properties, creando flussi di controllo chiari e immutabili.

Combinare le Tre Feature: Esempi Pratici

DTO Immutabile con Enum e Match

enum OrderAction: string {
    case Create = 'create';
    case Update = 'update';
    case Delete = 'delete';
}

readonly class OrderDTO {
    public function __construct(
        public string $orderId,
        public OrderAction $action,
        public array $data = [],
    ) {}
}

function processOrder(OrderDTO $dto): string {
    return match($dto->action) {
        OrderAction::Create => createOrder($dto->data),
        OrderAction::Update => updateOrder($dto->orderId, $dto->data),
        OrderAction::Delete => deleteOrder($dto->orderId),
    };
}

In questo esempio, OrderDTO è immutabile grazie alle readonly property; l'azione viene rappresentata da un enum, e la logica di routing è gestita dalla match expression. Il risultato è codice a prova di errore e facile da estendere.

State Machine Semplice

enum PaymentStatus: string {
    case Pending = 'pending';
    case Completed = 'completed';
    case Failed = 'failed';
    case Refunded = 'refunded';

    public function canTransitionTo(self $newStatus): bool {
        return match($this) {
            self::Pending => in_array($newStatus, [self::Completed, self::Failed], true),
            self::Completed => $newStatus === self::Refunded,
            self::Failed, self::Refunded => false,
        };
    }
}

Le transizioni di stato sono espresse con match, e l'immutabilità delle proprietà readonly garantisce che lo stato non venga alterato se non attraverso un processo controllato.

Best Practice e Avvertenze

Le readonly property non possono essere utilizzate con classi che richiedono lazy loading o riassegnazioni frequenti. Sono invece eccellenti per DTO, configurazioni e value object.

Gli enums, pur essendo tipi forti, non supportano l'ereditarietà (non si può estendere un enum). Usare interfacce per condividere comportamenti comuni.

La match expression va preferita allo switch per operazioni che coinvolgono valori discreti (enums, stringhe prevedibili). Tuttavia, per condizioni booleane complesse o range, un blocco if/elseif rimane più leggibile.

Infine, l'abbinamento di readonly, enums e match porta a un codice dichiarativo e funzionale, riducendo gli effetti collaterali e migliorando la testabilità.

Conclusione e Prossimi Passi

Readonly properties, enums e match expression non sono semplici aggiunte sintattiche: rappresentano un cambio di paradigma verso uno stile di programmazione più sicuro ed espressivo. Integrandole nel proprio flusso di lavoro, si ottiene codice più facile da ragionare, mantenere e testare.

Per approfondire, consulta la documentazione ufficiale PHP sulle readonly properties e la guida agli enum. Per un confronto con le novità di PHP 8.3 e 8.4, leggi il nostro articolo dedicato: Novità PHP 8.3 e 8.4: Typed Class Constants, Property Hooks e json_validate.

Sponsored Protocol

Ing. Calogero Bono

> AUTHOR_EXTRACTED

Ing. Calogero Bono

Co-founder di Meteora Web. Ingegnere informatico, sviluppo ecosistemi digitali ad alte prestazioni. AI, automazione, SEO tecnica e infrastrutture web. Scrivo di tecnologia per rendere complesso… semplice.

[ Read Full Dossier ]

Hai bisogno di applicare questa strategia?

Esegui il protocollo di contatto per iniziare un progetto con noi.

> INIZIA_PROGETTO

Sponsored

> MW_JOURNAL

> READ_ALL()