W3docs

final

The "final" keyword is a feature of object-oriented programming in PHP that allows a method, class or property to be marked as final, preventing it from being

The PHP final Keyword

final is an object-oriented keyword in PHP that locks down part of a class so that subclasses cannot change it. You can apply it to a class (no other class may extend it), to a method (no subclass may override it), or, since PHP 8.1, to a constant (no subclass may redefine it).

Marking something final is a deliberate design statement: "this behavior is intentional, and child classes must not alter it." Used well, it prevents accidental overrides, documents intent in code, and lets you reason about a class without worrying that a subclass quietly changed how it works. This page covers each form of final, when to reach for it, and the gotchas that trip people up.

Already comfortable with subclasses and overriding? final only makes sense in the context of PHP inheritance and classes and objects.

Final classes

A final class cannot be extended. Any attempt to declare a subclass produces a fatal error at compile time:

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

Use a final class when its behavior is complete and inheritance would be a misuse — for example a value object, a service whose contract you control, or a security-sensitive class where an overriding subclass could bypass a check.

Final methods

You can keep a class extendable but lock down individual methods. A final method can be inherited and called by subclasses, but it cannot be overridden:

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

This is the most common use of final: you want a class to be open for extension in general, but a specific method enforces an invariant (here, you can never withdraw more than the balance) that no subclass should be able to weaken.

Try it Yourself isn't available for this example.

A private method is effectively final already — it is not visible to subclasses, so marking a private method final is redundant (and PHP 8 emits a warning for final private, except on the constructor).

Final constants (PHP 8.1+)

Before PHP 8.1, a subclass could redefine an inherited constant. PHP 8.1 added final for constants so you can prevent that:

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

If you need constants that are part of a fixed contract — status codes, role names, configuration keys — final keeps every subclass honest. Learn more in class constants.

Final properties (PHP 8.4+)

Before PHP 8.4, final could not be applied to a property at all. PHP 8.4 added final properties: a final property can still be read and written, but a subclass may not redeclare it.

<?php

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

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

Note that final controls redeclaration, not mutability — the value can still be reassigned at runtime. To make a value unchangeable after construction, use a readonly property; the two modifiers are often combined (final public readonly string $model). On PHP 8.3 and earlier, marking any property final is a fatal error.

final vs. abstract

final and abstract are opposites and cannot be combined:

  • abstract means must be implemented by a subclass — it requires inheritance.
  • final means cannot be extended or overridden — it forbids inheritance.

Declaring final abstract class is a fatal error. See abstract classes for the other side of this coin.

When to use final

  • Lock an invariant. A final method guarantees critical logic (validation, security checks, billing) can't be silently changed downstream.
  • Signal "done" classes. A final class tells readers the design is intentional and not meant to be subclassed.
  • Prefer composition over inheritance. When you'd rather consumers wrap your class than extend it, final nudges them that way.

A common counter-argument: final can make code harder to test or mock, since you can't subclass a final class. The modern answer is to depend on interfaces (so you mock the interface, not the concrete class) — see interfaces. Reach for final when the constraint is genuinely part of the design, not as a blanket habit.

Conclusion

The final keyword closes a class, method, or constant to modification by subclasses, turning a design intention into a compiler-enforced rule. Use it on classes that are complete, on methods that protect invariants, and on constants that form a fixed contract — but remember it cannot be applied to properties and cannot be combined with abstract.

Practice

Practice
What does the 'final' keyword denote in PHP?
What does the 'final' keyword denote in PHP?
Was this page helpful?