W3docs

final

La parola chiave "final" in PHP permette di contrassegnare un metodo, una classe o una proprietà come finale, impedendone la sovrascrittura.

La parola chiave final in PHP

final è una parola chiave della programmazione orientata agli oggetti in PHP che blocca una parte di una classe in modo che le sottoclassi non possano modificarla. Puoi applicarla a una classe (nessun'altra classe può estenderla), a un metodo (nessuna sottoclasse può sovrascriverlo) oppure, da PHP 8.1, a una costante (nessuna sottoclasse può ridefinirla).

Contrassegnare qualcosa con final è una scelta progettuale deliberata: "questo comportamento è intenzionale e le classi figlie non devono alterarlo." Usata bene, previene sovrascritture accidentali, documenta le intenzioni nel codice e permette di ragionare su una classe senza preoccuparsi che una sottoclasse abbia modificato silenziosamente il suo funzionamento. Questa pagina tratta ogni forma di final, quando usarla e le insidie più comuni.

Hai già familiarità con le sottoclassi e l'override? final ha senso solo nel contesto dell'ereditarietà PHP e delle classi e oggetti.

Classi final

Una classe final non può essere estesa. Qualsiasi tentativo di dichiarare una sottoclasse produce un errore fatale in fase di compilazione:

<?php

final class PaymentGateway
{
    public function charge(float $amount): string
    {
        return "Charged $amount";
    }
}

// Fatal error: Class CryptoGateway cannot extend final class PaymentGateway
class CryptoGateway extends PaymentGateway {}

Usa una classe final quando il suo comportamento è completo e l'ereditarietà sarebbe un uso improprio — ad esempio un value object, un servizio il cui contratto controlli tu, o una classe legata alla sicurezza in cui una sottoclasse che esegue l'override potrebbe aggirare un controllo.

Metodi final

Puoi mantenere una classe estendibile ma bloccare singoli metodi. Un metodo final può essere ereditato e chiamato dalle sottoclassi, ma non può essere sovrascritto:

<?php

class Account
{
    protected float $balance = 0;

    // Subclasses may add behavior, but must not change how withdrawing works.
    final public function withdraw(float $amount): void
    {
        if ($amount > $this->balance) {
            throw new RuntimeException("Insufficient funds");
        }
        $this->balance -= $amount;
    }
}

class SavingsAccount extends Account
{
    public function addInterest(float $rate): void
    {
        $this->balance += $this->balance * $rate;
    }

    // Fatal error: Cannot override final method Account::withdraw()
    // public function withdraw(float $amount): void {}
}

Questo è l'uso più comune di final: vuoi che una classe sia aperta all'estensione in generale, ma un metodo specifico applica un invariante (qui, non puoi mai prelevare più del saldo disponibile) che nessuna sottoclasse deve poter indebolire.

"Provalo tu stesso" non è disponibile per questo esempio.

Un metodo private è già di fatto final — non è visibile alle sottoclassi, quindi contrassegnare un metodo privato come final è ridondante (e PHP 8 emette un avviso per final private, tranne che sul costruttore).

Costanti final (PHP 8.1+)

Prima di PHP 8.1, una sottoclasse poteva ridefinire una costante ereditata. PHP 8.1 ha aggiunto final per le costanti, così da poterlo impedire:

<?php

class HttpStatus
{
    final public const OK = 200;
}

class ApiStatus extends HttpStatus
{
    // Fatal error: ApiStatus::OK cannot override final constant HttpStatus::OK
    // public const OK = 201;
}

Se hai bisogno di costanti che facciano parte di un contratto fisso — codici di stato, nomi di ruolo, chiavi di configurazione — final garantisce che ogni sottoclasse le rispetti. Scopri di più nelle costanti di classe.

Proprietà final (PHP 8.4+)

Prima di PHP 8.4, final non poteva essere applicato alle proprietà. PHP 8.4 ha introdotto le proprietà final: una proprietà final può ancora essere letta e scritta, ma una sottoclasse non può ridichiarare.

<?php

class Car
{
    final public string $model = "Toyota";
}

class Toyota extends Car
{
    // Fatal error: Cannot override final property Car::$model
    // public string $model = "Corolla";
}

Nota che final controlla la ridichiarazione, non la mutabilità — il valore può ancora essere riassegnato in fase di esecuzione. Per rendere un valore immutabile dopo la costruzione, usa una proprietà readonly; i due modificatori vengono spesso combinati (final public readonly string $model). Su PHP 8.3 e versioni precedenti, contrassegnare qualsiasi proprietà come final è un errore fatale.

final vs. abstract

final e abstract sono opposti e non possono essere combinati:

  • abstract significa deve essere implementato da una sottoclasse — richiede l'ereditarietà.
  • final significa non può essere esteso o sovrascritto — vieta l'ereditarietà.

Dichiarare final abstract class è un errore fatale. Vedi le classi astratte per l'altro lato di questa medaglia.

Quando usare final

  • Bloccare un invariante. Un metodo final garantisce che la logica critica (validazione, controlli di sicurezza, fatturazione) non possa essere modificata silenziosamente in seguito.
  • Segnalare classi "complete". Una classe final comunica ai lettori che il design è intenzionale e non è pensato per essere esteso tramite sottoclassi.
  • Preferire la composizione all'ereditarietà. Quando preferisci che i consumer racchiudano la tua classe piuttosto che estenderla, final li spinge in quella direzione.

Un argomento contrario comune: final può rendere il codice più difficile da testare o simulare (mock), poiché non è possibile creare una sottoclasse di una classe final. La risposta moderna è dipendere dalle interfacce (così si fa il mock dell'interfaccia, non della classe concreta) — vedi le interfacce. Ricorri a final quando il vincolo è genuinamente parte del design, non come abitudine indiscriminata.

Conclusione

La parola chiave final chiude una classe, un metodo o una costante alla modifica da parte delle sottoclassi, trasformando un'intenzione progettuale in una regola applicata dal compilatore. Usala su classi complete, su metodi che proteggono invarianti e su costanti che formano un contratto fisso — ma ricorda che non può essere applicata alle proprietà e non può essere combinata con abstract.

Esercizio

Pratica
Cosa indica la parola chiave 'final' in PHP?
Cosa indica la parola chiave 'final' in PHP?
Was this page helpful?