PHP interfaces allow the definition of constants in an interface, e.g.
interface FooBar { const FOO = 1; const BAR = 2; } echo FooBar::FOO; // 1
Any implementing class will automatically have these constants available, e.g.
class MyFooBar implement FooBar { } echo MyFooBar::FOO; // 1
My own take on this is that anything Global is Evil. But I wonder if the same applies to Interface Constants. Given that Coding against an Interface is considered good practise in general, is using Interface Constants the only constants that are acceptable to use outside a class context?
While I am curious to hear your personal opinion and whether you use Interface constants or not, I'm mainly looking for objective reasons in your answers. I dont want this to be a Poll Type question. I'm interested in what effect using interface constants has on Maintainability. Coupling. Or Unit Testing. How does it relate to SOLID PHP? Does it violate any coding principles that are considered Good Practise in PHP? You get the idea …
Note: there is a similar question for Java that listed some quite good reasons why they are Bad Practice, but since Java isn't PHP, I felt it justified to ask it within the PHP tag again.
In my opinion, the fields in a interface, should not be constants to the whole project, they are only means for the interface and the interfaces extend it and the classes which are implement these interfaces or have a close relation with them. They should be used within a certain range not global.
Java programmers commonly define constants inside their interfaces, if it makes design sense. You can do so using variables in an interface because the values will be present instantly at runtime and their values shared among all classes implementing your interface, because they are static and final.
You declare a constant within a procedure or in the declarations section of a module, class, or structure.
A Java interface can contain constants. In some cases it can make sense to define constants in an interface. Especially if those constants are to be used by the classes implementing the interface, e.g. in calculations, or as parameters to some of the methods in the interface.
Well, I think that it boils down to the difference between good and good enough.
While in most cases you can avoid the use of constants by implementing other patterns (strategy or perhaps flyweight), there is something to be said for not needing a half dozen other classes to represent a concept. I think what it boils down to, is how likely is there a need for other constants. In other words, is there a need to extend the ENUM provided by the constants on the interface. If you can foresee needing to expand it, then go with a more formal pattern. If not, then it may suffice (it'll be good enough, and hence be less code to write and test). Here's an example of a good enough and a bad use:
Bad:
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 that I chose those examples is simple. The User
interface is defining an enum of user types. This is very likely to expand over time and would be better suited by another pattern. But the HTTPRequest_1_1
is a decent use-case, since the enum is defined by RFC2616 and will not change for the lifetime of the class.
In general, I don't see the problem with constants and class constants as being a global problem. I see it as a dependency problem. It's a narrow distinction, but a definite one. I see global problems as in global variables which are not enforced, and as such create a soft global dependency. But a hard-coded class creates an enforced dependency, and as such create a hard global dependency. So both are dependencies. But I consider the global to be far worse since it's not enforced... Which is why I don't like to lump class dependencies with global dependencies under the same banner...
If you write MyClass::FOO
, you're hard-coded to the implementation details of MyClass
. This creates a hard-coupling, which makes your code less flexible, and as such should be avoided. However, interfaces exist to permit exactly this type of coupling. Therefore MyInterface::FOO
doesn't introduce any concrete coupling. With that said, I wouldn't introduce an interface just to add a constant to it.
So if you're using interfaces, and you're very sure that you (or anyone else for that matter) won't need additional values, then I don't really see a huge issue with the interface constants... The best designs wouldn't include any constants or conditionals or magic-numbers or magic-strings or hard-coded anything. However, that adds additional time to the development, as you must consider the uses. My view is that most times it's absolutely worth taking the additional time to build a great solid design. But there are times when good enough really is acceptable (and it takes an experienced developer to understand the difference), and in those cases it's fine.
Again, that's just my view on it...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With