« A Super Productive Quarter At Mozilla | Consuming RabbitMQ messages with PHP » |
Anyone that is a regular reader here knows that I am a huge fan of interfaces, type hinting and polymorphism. Interfaces are one of the harder concepts in object oriented programming, and object oriented PHP in particular. But as much a fan as I am of interfaces, the truth is that sometimes you can go overboard with interfaces.
We like to imagine that our object oriented code follows all the great things that we know object oriented programming should be: it’s testable, extendable, reusable. But the honest truth is that some objects will never have a peer; there will never be another object that implements the same interface but behaves differently.
Where interfaces truly shine is when they’re used for an object that performs a specific task, but does it differently from another object that performs the same specific task. For example, a caching interface can inform your application how to cache data, abstracting away the specifics of Memcached, APC or other caching mechanisms you might choose to utilize.
Sometimes your objects aren’t designed to be reused. If that’s the case, there’s no logical reason why they should implement an interface.
A controller, for example, doesn’t have an interface. You’ll never re-implement a specific controller type in a different way. Or take the value object: having it implement an interface doesn’t make sense because the value object won’t ever be implemented any other way.
Interfaces are tremendously useful for testing since they can be implemented easily as mock objects. But for concrete classes that have no dependencies there’s no reason not to use the object; moreover, PHPUnit’s getMock() method can imitate any object you might need to inject or work with. This allows you to test those one-off objects that don’t have interfaces without having to worry about the dependencies they introduce.
It’s perfectly reasonable to type hint on concrete classes like value objects. This is because you actually do want an instance of that particular object. There’s no reason to create an interface for the implementation of a type hint.
I’ll still continue to write interfaces, and encourage others to do so. They’re a great tool for reuse. But they are not a required tool, and they’re not a universal tool that should be applied all the time. Interfaces should be implemented when they solve a specific problem, and left out when they don’t, just like every other object oriented concept.
Brandon Savage is the author of Mastering Object Oriented PHP and Practical Design Patterns in PHP
Posted on 6/4/2013 at 7:00 am
Simon wrote at 6/4/2013 8:13 am:
Oh, god, yes. My experience is Java rather than PHP, but over the years, I’ve seen far too many pointless interfaces, and more generally, unnecessary abstractions.
My particular annoyance is data access objects, where an interface allows an SQL layer to be effortlessly swapped for some other system (e.g LDAP, ORM, etc). Nice in theory, but after ten years of development on that project, not one of those interfaces has ever had more than one implementation.
KingCrunch wrote at 6/4/2013 9:01 am:
Nobody said, that the possibility to _replace_ an instance is the only reason to use interfaces. Maybe you simply want to add some logging and/or caching without touching the class itself (Buzzword: “Cross-dependencies”). If you didn’t create the interface in the first place and you created type-hints against the concrete class instead, it is not that easy anymore to (e.g.) add logging, or caching without changes in the class itself (or hacks. OK, or AOP ;)).
Oh, and btw: It is (in my opinion) not possible to see, whether or not a class should be replaced some time, or even “is replaceable” :)
« A Super Productive Quarter At Mozilla | Consuming RabbitMQ messages with PHP » |