Well, I think it comes down to the difference between good and good enough.
Although in most cases you can avoid using constants by implementing other templates (strategy or possibly flies), there is something to say because you do not need half a dozen other classes to represent the concept. I think it comes down to how probable the need for other constants is. In other words, is there a need to extend the ENUM provided by the interface constants. If you can foresee the need for its expansion, go to a more formal template. If not, then this may be enough (it will be good enough, and therefore there will be less code for writing and testing). Here is an example of good enough and bad use:
Poorly:
interface User { const TYPE_ADMINISTRATOR = 1; const TYPE_USER = 2; const TYPE_GUEST = 3; }
Good enough:
interface HTTPRequest_1_1 { const TYPE_CONNECT = 'connect'; const TYPE_DELETE = 'delete'; const TYPE_GET = 'get'; const TYPE_HEAD = 'head'; const TYPE_OPTIONS = 'options'; const TYPE_POST = 'post'; const TYPE_PUT = 'put'; public function getType(); }
Now, the reason I chose these examples is simple. The User interface defines an enumeration of user types. This is likely to expand over time and will better fit another pattern. But HTTPRequest_1_1 is a worthy use case, since the enumeration is defined by RFC2616 and will not change for the lifetime of the class.
In general, I do not see the problem with class constants and constants as a global problem. I see this as a dependency problem. This is a narrow distinction, but a definite one. I see global problems, both in global variables that are not applied, and as such create soft global dependency. But a hard-coded class creates a forced dependency and thus creates a hard global dependency. So both are dependencies. But I believe that globality will be much worse, because it does not apply ... That's why I do not like to generalize class dependencies with global dependencies under the same banner ...
If you write MyClass::FOO , you are tightly attached to the details of the MyClass implementation. This creates a tight connection, which makes your code less flexible and should be avoided as such. However, there are interfaces that allow this type of communication. Therefore, MyInterface::FOO does not introduce any specific relationship. With that said, I would not introduce an interface to add a constant to it.
So, if you use interfaces, and you are very sure that you (or someone else in this case) will not need additional values, then I really do not see a huge problem with the interface constants ... The best projects will not include any constants or conditional numbers or magic numbers or magic strings or hard-coded things. However, this adds extra time for development, as you should consider usage. I believe that in most cases it is absolutely necessary to spend extra time creating an excellent durable design. But there are times when itβs quite acceptable (and an experienced developer is required to understand the difference), and in these cases this is normal.
Again, this is just my view on this ...