Renaming a parent method is a silent break in every child, and 8.3 finally gives a way to say a method is meant to override something.
class Base
{
protected function formatRow(array $row): string { /* ... */ }
}
class Report extends Base
{
#[Override]
protected function formatRow(array $row): string { /* ... */ }
}
// rename Base::formatRow and the child is now a fatal error
// rather than dead code.
// it works for interface methods too, which is the part
// people miss.
Adding it across the codebase found four methods that had stopped overriding anything, the oldest dating to a 2019 rename — all four were dead, and one had been the subject of a bug report that was closed as not reproducible. What it does not catch is a signature that changed rather than a name, because that is a compatibility error already. A lint rule requiring the attribute on new overrides is what keeps the guarantee.