Constants in traits arrived in 8.2 and the first thing I did with the feature was decide not to use it.
trait HasStatus
{
public const DEFAULT = 'pending'; // 8.2
public function status(): string { /* ... */ }
}
// the conflict rules, which are the reason to be careful:
// a class using two traits that both define DEFAULT is a
// fatal error, and insteadof does NOT resolve constants.
// there is no way to pick one.
The method conflict rules have an escape hatch and the constant rules do not, which makes a trait constant a name that can collide with no resolution available. That is a small thing on its own and it compounds the general problem: a trait is copy-paste with a compiler, and the more state it carries the harder it is to reason about what a class actually contains. An interface with a class constant, or composition, says the same thing without the collision.