Pros and cons of interface constants

PHP interfaces allow you to define constants in an interface, for example

interface FooBar { const FOO = 1; const BAR = 2; } echo FooBar::FOO; // 1 

Any implementation class will automatically have these constants, for example.

 class MyFooBar implement FooBar { } echo MyFooBar::FOO; // 1 

Actually, this is something global - evil. But I wonder what about the interface constants. Given that coding with an interface is considered good practice in general, does interface constants use the only constants that are acceptable for use outside the context of the class?

While I am curious to hear your personal opinion and whether you use interface constants or not, I mainly looked for objective reasons in your answers. I do not want this to be a survey type question. I am interested in what effect the use of interface constants has to ensure operability. Communication Or unit testing. How does this relate to SOLID PHP? Does it violate any coding principles that are considered good practice in PHP? You get the idea ...

Note. There is a similar question for Java that lists some pretty good reasons why they are bad practice, but since Java isn’t PHP, I found it justified to ask it again in the PHP tag.

+85
php interface constants
Mar 18 '11 at 10:27
source share
2 answers

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 ...

+104
Mar 18 2018-11-18T00:
source share

I think it is usually best to treat constants, specially listed constants, as a separate type ("class") from your interface:

 define(TYPE_CONNECT, 'connect'); define(TYPE_DELETE , 'delete'); define(TYPE_GET , 'get'); define(TYPE_HEAD , 'head'); define(TYPE_OPTIONS, 'options'); define(TYPE_POST , 'post'); define(TYPE_PUT , 'put'); interface IFoo { function /* int */ readSomething(); function /* void */ ExecuteSomething(/* int */ param); } class CBar implements IFoo { function /* int */ readSomething() { ...} function /* void */ ExecuteSomething(/* int */ param) { ... } } 

or, if you want to use the class as a namespace:

 class TypeHTTP_Enums { 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'; } interface IFoo { function /* int */ readSomething(); function /* void */ ExecuteSomething(/* int */ param); } class CBar implements IFoo { function /* int */ readSomething() { ...} function /* void */ ExecuteSomething(/* int */ param) { ... } } 

Not that you use only constants, you use the concept of enumerated values ​​or enumerations, which are a set of restricted values ​​that are of a particular type with a specific use ("domain"?)

+8
Mar 28 '11 at 16:33
source share



All Articles