Interfacing The PHP World Would Be Good
With some precious free time today, I sat down to read Lukas Smith's Interfacing The PHP World. It was good timing since last night I heard someone complain, again, about tight coupling in Zend Framework so I was in a good frame of mind to digest the blog post.
Before we start, tight coupling exists in a scenario where any one class relies upon another concrete class type (usually enforced using type hinting). Because the coupling is between two concrete classes, the only way to bypass it is through monkey patching the dependent class. Monkey patching has long been the lazy option for fixing stuff in PHP and we're trying to get away from it. Loose coupling, on the other hand, exists when a class is dependent on an interface. Because we can write any class that adheres to that interface, we can inject any class we can imagine so long as it implements that interface. This is a far simple and maintainable situation since a) we are favouring composition over inheritance and b) there's no fracking monkey patching!
The common denominator in loose coupling is therefore ensuring your dependent classes accept any dependency matching an agreed interface. Question: Whose interface are we agreeing on?
Every PHP framework has it's own unique set of interfaces for common operations such as logging, caching, http clients, filtering, validation, etc. This creates a situation where a framework tends to be loosely coupled but only within the scope of its own interfaces. Thus, Symfony 2 components using HTTP can't simply swap the existing client for Zend\Http\Client. Symfony 2 and Zend Framework 2 do not abide by an agreed interface - they have two distinct and incompatible ones.
Loose coupling is therefore a bad joke. It is a narrowly defined concept usually described within the scope of one particular application. We never really apply the concept across multiple applications written with different frameworks because, at that point, the disparate interfaces of both frameworks would immediately make loose coupling unobtainable.
That is the crux of Lukas' idea - and it's a really good idea. More interestingly, it's almost an even better idea for Zend Framework 2 than Symfony 2. Zend Framework would benefit even more because we also distribute scores of component libraries and the interfaces relied upon make using Zend Framework components almost certainly contingent on the use of many other Zend Framework components to meet dependencies.
A simple example is Zend\Feed\Reader. For want of an agreed HTTP Client interface, we're stuck with usingaZend\Http\Client. You could use Symfony 2as client but then you'd need to create an abstract class to mediate between that client's methods and the mismatched interface implemented by Zend\Http\Client. The result is therefore obvious - it requires more work and you'll probably end up using both HTTP Clients rather than taking the hard road. Throw in a few more framework odds and ends, and you can be putting a lot of duplicated functionality to work just because they won't speak the same language.
This is actually a bad deal for PHP programmers. Instead of one common interface for HTTP Clients, you have dozens. They won't interoperate, they can't be swapped for each other, and they directly encourage framework specific implementations instead of interface specific implementations (i.e. with common interfaces the need to duplicate functionality because of NIH Syndrome might be significantly reduced). You're also forgetting those libraries who feel compelled to internally and eternally duplicate HTTP client functions rather than simply depending on a preferred client using a common interface. Not to mention half those mini-clients are poorly written and tend to disable SSL certificate verification because they can't be arsed about handling the errors from invalid certs even if it does amount to putting your users' private data at a real risk of being compromised.
Truncated by Planet PHP, read more at the original (another 3735 bytes)