4

Do some of you here on Stack Overflow think that this could be a good implementation or not?

For example I have an interface called RequestInterface which has 5 constants:

interface RequestInterface {
    const GET = 1;
    const POST = 2;
    const PUT = 3;
    const DELETE = 4;
    const HEAD = 5;

    public function getType();
    // ... some other methods declarations
}

And then for each constant a class which implements that interface, e.g. the PostRequest:

class PostRequest implements RequestInterface {
     public function getType() {
          return RequestInterface::POST
     }
}

The PUT request:

class PutRequest implements RequestInterface {
     public function getType() {
          return RequestInterface::PUT
     }
}

And so for the other classes.

I know that using constants inside an interface is considered an Anti-Pattern by some, but what would you say about the example I made, and what could be a possible better solution for such a case?

EDIT: @pid you advise me to use the get_class() or is_a() function, so e.g. if I have another class which uses that RequestInterface I could get rid of those constants and simply use even instanceof to determine the type of the RequestInterface?

// inside another class which uses a RequestInterface
public function someMethod(RequestInterface $request) {
    if ($request instanceof PostRequest) {
       // Request is a post...
    }
}
tonix
  • 6,671
  • 13
  • 75
  • 136
  • 1
    I do not think that *static* data - eg. constants - should have anything to do with polymorphism (and by extension, interfaces). There is simply no benefit (esp. here) added while something like `return HttpVerb::POST` is more clear to me (and is obtained by separating the static data from the interface into it's own type/container). – user2864740 Jul 28 '14 at 22:24
  • 1
    The type is already named through the class. You can use the class name as identifier. – feeela Jul 28 '14 at 22:35
  • 2
    please look at this question it fits perfect on your question http://stackoverflow.com/questions/5350672/pros-and-cons-of-interface-constants – ins0 Jul 28 '14 at 22:35
  • @ins0 Yeah it is a very similar question, however it seems to me that no one there showed a possible workaround or a possible alternative in such a case... What do you think? – tonix Jul 29 '14 at 14:08
  • @user2864740 So you are saying that you would create another type, for example an HttpVerb abstract class or interface which contains those constants and then use them inside RequestInterface implementations? – tonix Jul 29 '14 at 14:10
  • @user3019105 Not an "interface" or "abstract class" - this has nothing to do with polymorphism so those concepts are not needed. Simply use a namespace/container (eg "static class", which will never be instantiated) for constants. But yes, the constants would be contained in a separate type that act-like an enum/set over the [static] members or constants therein. – user2864740 Jul 29 '14 at 19:23

1 Answers1

2

Consider that the interface definition is most likely exposed to a client application. You don't want to have implementation details in that file. A client programmer wants to look at your interface definition and just see what matters, that is the API contract of which the meaning has been described in the documentation.

The actual value of the constants has no importance whatsoever. In fact, exposing this by putting it in the interface definition nullifies the usage of constants... ignore the actual values in favor of mnemonic/onomatopoeic terms (onomato... => it is what it sounds like, no documentation/explanation needed to understand it straight away).

pid
  • 11,472
  • 6
  • 34
  • 63
  • Thank you for your explanation, anyway what do you think could be wrong in my example and could be improved with a more scalable solution? How would you handle such a concern in your project? – tonix Jul 29 '14 at 14:15
  • 1
    feela's comment `The type is already named through the class. You can use the class name as identifier.` is very useful. You don't need the constants at all, you can infer the difference from the actual type with `get_class()`. So you don't need `gettype()`. In this special case everything seems to dissappear because you are using the paradigm and not a clumsy work-around. To test an instance you can use [is_a](http://php.net/manual/en/function.is-a.php). – pid Jul 29 '14 at 14:20
  • All right so if I have a method in another class which uses the RequstInterface as type hint, I should recover the type of request using the *instanceof* directive? Please check my edit. – tonix Jul 29 '14 at 14:46
  • Yes and no. The code you wrote is correct, but you defy the meaning of the interface. As a contract, the interface will have methods. Your consumer of the interface should not distinguish with if/switch the actual type, but just use the methods of the interface. This way you `code against an abstraction` (the interface). Look here how to leverage polymorphism and interfaces: http://stackoverflow.com/questions/2697783/what-does-program-to-interfaces-not-implementations-mean – pid Jul 29 '14 at 15:03
  • Thanks for the nice link you posted! I guess that separate the constants from the interface and use a proper abstract class or an interface like an *enum*, as *this. __curious_geek* in the example he made in the link you posted, would be a better solution, what do you think of such approach? – tonix Jul 29 '14 at 15:36
  • 1
    You are mixing some concepts here. Interfaces are language constructs. What you see over there is the Factory Pattern, which tells you how to best use those language constructs to obtain the desired functionality. They don't exclude each other, on the contrary, the pattern is exalted by clean separation of interfaces from implementation intrinsics. As always, a pattern may be overshoot in some cases. But if it's not, it's extremely helpful. Before patterns make any sense you need to study the SOLID principles, so you should learn language constructs => SOLID => patterns. – pid Jul 30 '14 at 10:08