A class constant could always be overridden by a subclass, silently, and there was no way to say it should not be.
class Http
{
final public const VERSION = '1.1';
public const TIMEOUT = 30;
}
class Custom extends Http
{
public const TIMEOUT = 5; // fine, and intended
public const VERSION = '2'; // Fatal error
}
// note: enum constants are implicitly final,
// as are all constants in a final class.
This matters most for a constant that is part of a protocol rather than a default — a wire format version, a header name, a hash algorithm identifier. Overriding those silently produces a subclass that claims to be the parent and is not. Interface constants became overridable in 8.1 at the same time, which is a change in the opposite direction and is the reason final is now needed to express what interface constants used to imply.