Abstract and final

Abstract Classes, final Classes and final Promoted Properties

An abstract class cannot be instantiated; children must implement its abstract methods, which suits a template method. final forbids extending a class or overriding a method, constant (8.1) or property (8.4); PHP 8.5 allows it on promoted parameters, implying public.

A template method in an abstract class, with a final leaf classPHP
<?php
abstract class Discount {
  public function __construct(final public string $code) {}      // PHP 8.5: final promoted
  abstract protected function amountOff(int $sub): int;           // no body
  public function apply(int $sub): int { return max(0, $sub - $this->amountOff($sub)); }
}
final class PercentOff extends Discount {
  public function __construct(string $code, private int $pct) { parent::__construct($code); }
  protected function amountOff(int $sub): int { return intdiv($sub * $this->pct, 100); }
}
echo new PercentOff('SAVE10', 10)->apply(4200), "\n";
try { new Discount('X'); } catch (Error $e) { echo $e->getMessage(), "\n"; }
Output
3780
Cannot instantiate abstract class Discount

Breaking final is a compile-time fatal error that stops the whole file: a class Bad that redeclares $code gets "Cannot override final property Discount::$code", and one extending PercentOff gets "Class Bad cannot extend final class PercentOff". Make leaf classes final.