While type hinting is important to help improve your codebase usage and testing. For all the fun and joy it brings it can also lead to some of the worst maintenance hell if it is not done correctly. As one famous Uncle Ben used to say with great power comes great responsibility so here’s a quick reminder on how to properly type-hint.
To illustrate this, I will use the Carbon
package. This is in no way shape or form a criticism of the package but I think it’s usage makes it a great use case:
Let’s say we want to change a date. I’m pretty sure that this piece of code was recently added to a codebase near you.
Carbon\Carbon
is a mutable child of PHP’s DateTime
class. In 2022, we should stop using DateTime
. The class is mutable which means that the number of unpredictable things, this piece of code can do in your codebase is frightening.
Thanksfully for us, the code can be improved by just doing this.
This way side effect are prevented as Carbon\CarbonImmutable
is an immutable child of PHP’s DateTimeImmutable
class. Last but not least, if this method is part of an interface or of the public API, I would instead suggest doing this:
This way the public API no longer rely on a specific PHP package (it’s decoupled), only this specific implementation does which is OK.
But what about when you do not need to mutate your object ?
There again by using Carbon
we largely limit who or what can potentially quickly interact with our API. Instead a way forward would be to do the following:
The code has not changed but by using the CarbonInterface
interface, a child interface of DateTimeInterface
we allow any Carbon
instance mutable or not to use the method.
But wait, since the code is not even changing or doing any funny stuff with date what we should really do is the following:
The following code will work everywhere regardless of the presence of the Carbon
package.
TL;DR:
- is Type-hinting fun: ✅
- should we still use
Carbon
(the instance) andDateTime
: ❌ - should we use
CarbonImmutable
andDateTimeImmutable
: ✅ - Rely on contracts and avoid specific implementations or hard coupling when possible