Published on 12 June 2014 by @mathiasverraes
PHP allows only a single constructor per class. That’s rather annoying. We’ll probably never have proper constructor overloading in PHP, but we can at least enjoy some of the benefits. Let’s take a simple Time value object. Which is the best way of instantiating it?
The only correct answer is “it depends”. Both are correct from the point of view of the domain. Supporting both is an option:
This is terribly ugly. It makes using the Time class rather confusing. And what happens if we need to add more ways to instantiate Time?
Or if we want to support numeric strings as well as integers?
(Note: in production code, I would make my Time class a lot more idiot-proof.)
Let’s add some public static methods to instantiate Time. This will allow us to get rid of the conditionals (which is always a good thing!).
Every method now satisfies the Single Responsibility Principle. The public interface is clear and understandable interface, and the implementations are straightforward. Are we done?
Well, something is bothering me:
__construct($hours, $minutes) kinda sucks: it exposes the internals of the Time value object, and we can’t change the interface because it is public. Imagine that for some reason, we want Time to store the string representation and not the individual values.
This is ugly: we go through all the trouble of splitting up the string, only to rebuild it in the constructor.
Do we even need a constructor now that we have named constructors? Of course not! They are just an implementation detail, that we want to encapsulate behind meaningful interfaces. So we make it private:
Now that the constructor is no longer public, we can choose to refactor all the internals of Time as much as we want. For example, sometimes you’ll want every named constructor to assign properties without passing them through a constructor:
Our code begins to clean up nicely, and our Time class now has some very useful ways of being instantiated. As it happens with better design, other, previously hidden design flaws, start to become visible. Look at the interface for Time:
Notice anything? We’re mixing no less than three languages:
fromStringis a PHP implementation detail;
fromValuesis a sort of generic programming term;
fromMinutesSinceMidnightis part of the domain language.
Being a language geek and Domain-Driven Design aficionado, I can’t let this pass. As Time is part of our domain, my preferred style is to find inspiration in the Ubiquitous Language.
(If you worry about the extra characters you’d need to type, get an editor with contextual code completion.)
This focus on the domain, gives you some great options:
Granted, that’s not always better. In the case of Time, I might stick to fromString, because maybe at this level of detail in our code, we want to serve the programmer more than the domain. I might even provide both options. But at least, thanks to named constructors, we now have options.
Follow @mathiasverraes on Twitter.
|Tactical Domain-Driven Design||Laracon EU||Workshop||Amsterdam, NL||Aug|
|Experiencing Domain-Driven Design||Value Object Comm.V||Workshop||Amsterdam, NL||Sep 7-9|
|Applying Domain-Driven Design to TYPO3||TYPO3 Developer Days||Workshop||Nürnberg, DE||Aug 31|
|Temporal Modelling||TYPO3 Developer Days||Talk||Nürnberg, DE||Sep 1|
|DDDinPHP||1 day training||workshop||Leuven, BE||Dec 16|
This work by Mathias Verraes is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 License.