W3docs

final

Das Schlüsselwort "final" in PHP markiert Klassen, Methoden oder Konstanten als nicht überschreibbar und schützt so wichtige Designentscheidungen.

Das PHP-Schlüsselwort final

final ist ein objektorientiertes Schlüsselwort in PHP, das einen Teil einer Klasse sperrt, sodass Unterklassen ihn nicht verändern können. Es kann auf eine Klasse (keine andere Klasse darf sie erweitern), eine Methode (keine Unterklasse darf sie überschreiben) oder seit PHP 8.1 auf eine Konstante (keine Unterklasse darf sie neu definieren) angewendet werden.

Etwas als final zu markieren ist eine bewusste Designentscheidung: „Dieses Verhalten ist absichtlich, und Kindklassen dürfen es nicht ändern." Richtig eingesetzt verhindert es versehentliches Überschreiben, dokumentiert die Absicht im Code und ermöglicht es, eine Klasse zu verstehen, ohne befürchten zu müssen, dass eine Unterklasse ihre Funktionsweise still verändert hat. Diese Seite behandelt jede Form von final, wann man es einsetzen sollte, und die Fallstricke, über die man leicht stolpert.

Bereits vertraut mit Unterklassen und Überschreiben? final macht nur im Kontext von PHP-Vererbung und Klassen und Objekten Sinn.

Finale Klassen

Eine final-Klasse kann nicht erweitert werden. Jeder Versuch, eine Unterklasse zu deklarieren, führt zu einem schwerwiegenden Fehler zur Kompilierzeit:

<?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 {}

Verwenden Sie eine finale Klasse, wenn ihr Verhalten vollständig ist und Vererbung ein Missbrauch wäre — zum Beispiel bei einem Value Object, einem Service, dessen Vertrag Sie kontrollieren, oder einer sicherheitskritischen Klasse, bei der eine überschreibende Unterklasse eine Prüfung umgehen könnte.

Finale Methoden

Eine Klasse kann erweiterbar bleiben, während einzelne Methoden gesperrt werden. Eine final-Methode kann von Unterklassen geerbt und aufgerufen werden, aber nicht überschrieben werden:

<?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 {}
}

Dies ist die häufigste Verwendung von final: Sie möchten, dass eine Klasse grundsätzlich erweiterbar ist, aber eine bestimmte Methode erzwingt eine Invariante (hier kann man nie mehr abheben als der Kontostand), die keine Unterklasse abschwächen darf.

„Probier es selbst" ist für dieses Beispiel nicht verfügbar.

Eine private-Methode ist bereits effektiv final — sie ist für Unterklassen nicht sichtbar, daher ist das Markieren einer privaten Methode als final redundant (und PHP 8 gibt für final private eine Warnung aus, außer beim Konstruktor).

Finale Konstanten (PHP 8.1+)

Vor PHP 8.1 konnte eine Unterklasse eine geerbte Konstante neu definieren. PHP 8.1 hat final für Konstanten eingeführt, damit dies verhindert werden kann:

<?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;
}

Wenn Sie Konstanten benötigen, die Teil eines festen Vertrags sind — Statuscodes, Rollennamen, Konfigurationsschlüssel — stellt final sicher, dass jede Unterklasse diese einhält. Mehr dazu in Klassenkonstanten.

Finale Eigenschaften (PHP 8.4+)

Vor PHP 8.4 konnte final überhaupt nicht auf eine Eigenschaft angewendet werden. PHP 8.4 hat final-Eigenschaften eingeführt: Eine final-Eigenschaft kann weiterhin gelesen und geschrieben werden, aber eine Unterklasse darf sie nicht neu deklarieren.

<?php

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

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

Beachten Sie, dass final die Neudeklaration kontrolliert, nicht die Veränderlichkeit — der Wert kann zur Laufzeit noch neu zugewiesen werden. Um einen Wert nach der Konstruktion unveränderlich zu machen, verwenden Sie eine readonly-Eigenschaft; die beiden Modifizierer werden häufig kombiniert (final public readonly string $model). Auf PHP 8.3 und früher ist das Markieren einer Eigenschaft als final ein schwerwiegender Fehler.

final vs. abstract

final und abstract sind Gegensätze und können nicht kombiniert werden:

  • abstract bedeutet, muss von einer Unterklasse implementiert werden — es erfordert Vererbung.
  • final bedeutet, kann nicht erweitert oder überschrieben werden — es verbietet Vererbung.

Die Deklaration von final abstract class ist ein schwerwiegender Fehler. Siehe abstrakte Klassen für die andere Seite dieser Medaille.

Wann sollte man final verwenden?

  • Eine Invariante sperren. Eine final-Methode garantiert, dass kritische Logik (Validierung, Sicherheitsprüfungen, Abrechnung) nicht stillschweigend geändert werden kann.
  • „Fertige" Klassen kennzeichnen. Eine final-Klasse signalisiert dem Leser, dass das Design bewusst gewählt und nicht zur Unterklassenbildung gedacht ist.
  • Komposition gegenüber Vererbung bevorzugen. Wenn Konsumenten Ihre Klasse lieber einbetten als erweitern sollen, lenkt final sie in diese Richtung.

Ein häufiges Gegenargument: final kann Code schwerer testbar oder mockbar machen, da man eine finale Klasse nicht unterklassen kann. Die moderne Antwort lautet, von Interfaces abhängig zu sein (man mockt das Interface, nicht die konkrete Klasse) — siehe Interfaces. Greifen Sie auf final zurück, wenn die Einschränkung wirklich Teil des Designs ist, nicht als pauschale Gewohnheit.

Fazit

Das Schlüsselwort final schließt eine Klasse, Methode oder Konstante vor Änderungen durch Unterklassen ab und macht eine Designabsicht zu einer vom Compiler erzwungenen Regel. Verwenden Sie es bei vollständigen Klassen, bei Methoden, die Invarianten schützen, und bei Konstanten, die einen festen Vertrag bilden — aber denken Sie daran, dass es nicht auf Eigenschaften angewendet werden kann und nicht mit abstract kombiniert werden darf.

Übungen

Übung
Was bezeichnet das Schlüsselwort 'final' in PHP?
Was bezeichnet das Schlüsselwort 'final' in PHP?
Was this page helpful?