Published on 16 February 2013 by @mathiasverraes
I’m a big fan of Value Objects, as they are very helpful in encapsulating behavior, and communicating intent. In fact, as a friend remarked, Value Objects are the heart and soul of Object Oriented Programming. Discussing the uses of Value Objects is not what I want to talk about here though.
Let’s set up two simple examples first:
Value Objects are one of the few places where using PHP’s magic __toString()
makes perfect sense. For single-value Value Objects like the
TwitterHandle, it’s obvious what should be in there. The
_toString() method simply returns the string representation.
Implemented inside TwitterHandle, it looks like this:
That’s quite self-evident, but what about other cases?
I had a couple of basic rules, that I have been using for a while for Value Objects. They were always implicit, but talking about them in a pair programming session made them explicit.
It’s tempting to use a __toString() method to render the Value Object in a View. More often than not, you would need to put presentation logic in your Value Object, and that’s a big no-no. It’s better to perform presentation rendering in a separate class or function, like a filter for your templating engine. It allows you to fine-tune the rendering for your use case.
Imagine we would have put the HTML rendering inside the TwitterHandle class; that would have been a sackable offense in my book! You’ll notice that this is especially important with Value Objects like dates and monetaries, where the rendering depends on the language.
Another temptation is to use string casting to get the numeric part of a measurement.
'5' is not a valid representation of a distance. Is it meters, centimeters, or inches? That information is now lost. If you start doing
calculations with that
'5', you may get nasty bugs. The kind of bugs that crash spacecrafts.
So make sure that the string represents all of the Value Object:
The most useful string representation you can come up with, is one that can be parsed back into the Value Object. For the TwitterHandle example, that’s again very easy, so let’s use DateRange as an example:
So as you can see,
'2013-01-01 - 2013-02-07' is a string representation of a DateRange, that can be parsed back into a DateRange object.
DateRange == parse(string(DateRange))
It works just as well for our other examples:
This will turn out to be very handy, especially when integrating with other systems, like a REST api or a database. But that’s something we’ll cover in a future blog post.
Follow @mathiasverraes on Twitter.
This work by Mathias Verraes is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 License.