Coupling refers to the degree of direct knowledge that one class has of another. This is not meant to be interpreted as encapsulation vs. non-encapsulation. It is not a reference to one class’s knowledge of another class’s attributes or implementation, but rather knowledge of that other class itself.
Strong coupling occurs when a dependent class contains a pointer directly to a concrete class which provides the required behaviour. Loose coupling occurs when the dependent class contains a pointer only to an interface, which can then be implemented by one or many concrete classes. Loose coupling provides extensibility to designs. A new concrete class can easily be added later that implements that same interface without ever having to modify and recompile the dependent class. Strong coupling does not allow this.
When you need two classes to collaborate with one another, try not to make them actually depend on each other, only on the minimal overlap of information that they must exchange. There are several ways to achieve this:
- Interfaces – e.g. instead of concrete class names in type hints.
- Dependency injection
- Inversion of control – “Don’t call me, I’ll call you.”
- Consistent use of well established Design Patterns.
Loose coupling makes unit testing easier. Tight coupling makes unit testing harder. Your ability to write unit tests for your code that are simple and independent of other classes is a great metric for how loosely coupled any bit of code is.
When you implement a major unit of functionality it should be in the form of a component. A component is a semi-autonomous sub-system of the larger overall system that can be added or removed from the system. It can be re-used by other systems. A component may consist of a collection of configuration data, PHP classes, view assets, database schema, and/or APIs but these disparate elements should act together to form a building block that can be mixed or matched with other building blocks from the collection of components.
An ideal component is sufficiently autonomous that it could be (perhaps packaged with a dependency on a core framework) open sourced, released to the general public, and found useful by others.