I ended up using user sectus’s suggestion of interfaces as it feels like the least-problematic way of handling this. Using an interface to store constants rather than API contracts has a bad smell about it though so maybe this issue is more about OO design than trait implementation.
interface Definition
{
const SOME_CONST = 'someconst';
const SOME_OTHER_CONST = 'someotherconst';
}
trait Base
{
// Generic functions
}
class A implements Definition
{
use Base;
}
class B implements Definition
{
use Base;
}
Which allows for:
A::SOME_CONST;
B::SOME_CONST;