Published on 04 April 2011 by @mathiasverraes
Whenever working with values in object oriented programming, it’s often a good idea to wrap them in a ValueObject. Money is a perfect candidate for a ValueObject: When talking about money, numbers are meaningless if they are not combined with a currency.
I’ve been using a very simple version of the Money pattern as described in Martin Fowler’s PoEAA. I couldn’t find a PHP implementation anywhere, so I decided to make my own little open source library for it. You can find it on my GitHub account (where else?).
An important aspect of ValueObjects is their immutability:
Let’s say Jim and Hannah both want to buy a copy of book priced at EUR 25.
Jim has a coupon for EUR 5.
$hannah_price are the same object, you’d expect Hannah to now have the reduced price as well. To prevent this problem, Money objects are immutable. With the code above, both
$hannah_price are still EUR 25:
The correct way of doing operations is:
My company made a whopping profit of 5 cents, which has to be divided amongst myself (70%) and my investor (30%). Cents can’t be divided, so I can’t give 3.5 and 1.5 cents. If I round up, I get 4 cents, the investor gets 2, which means I need to conjure up an additional cent. Rounding down to 3 and 1 cent leaves me 1 cent. Apart from re-investing that cent in the company, the best solution is to keep handing out the remainder until all money is spent. In other words:
$my_cut is 4 cents, and
$investors_cut is 1 cent. The order in which you allocate the the money is important:
$my_cut is 3 cents, and
$investors_cut is 2 cents.
At the moment my Money class has all the features that Fowler lists. You can see some more example by looking at the unit tests. I hope to add a lot stuff more if time permits: currency conversion, parsing of strings like ‘$2.00’ and ‘USD 2.00’, dealing with major units and subunits in currencies, etc. In any case, I hope it’s useful to somebody in it’s present form.
Follow @mathiasverraes on Twitter.
This work by Mathias Verraes is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 License.