Representing Money in PHP, Fowler-style

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?).

Immutability

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.

<?php
$jim_price = $hannah_price = new Money(2500, new Euro);

Jim has a coupon for EUR 5.

<?php
$coupon = new Money(500, new Euro);
$jim_price->subtract($coupon);

Because $jim_price and $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 $jim_price and $hannah_price are still EUR 25:

<?php
$jim_price->equals($hannah_price); // true

The correct way of doing operations is:

<?php
$jim_price = $jim_price->subtract($coupon);
$jim_price->lessThan($hannah_price); // true
$jim_price->equals(Money::euro(2000)); // true

Allocation

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:

<?php
$profit = new Money(5, new Euro);
list($my_cut, $investors_cut) = $profit->allocate(70, 30);

Now $my_cut is 4 cents, and $investors_cut is 1 cent. The order in which you allocate the the money is important:

<?php
list($investors_cut, $my_cut) = $profit->allocate(30, 70);

Now $my_cut is 3 cents, and $investors_cut is 2 cents.

Conclusion

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.



Upcoming

2017
Topic Event Type Location Date
Modelling Heuristics Workshop @ Domain-Driven Design Europe workshop Amsterdam, NL Feb 1
Conference Domain-Driven Design Europe 2017 organiser Amsterdam, NL Jan 31 - Feb 3
Domain-Driven Design Neos Conference workshop Hamburg, DE Mar 30
Keynote (TBD) Neos Conference keynote Hamburg, DE Mar 31
Older entries...

Blog Atom

2016

2015

2014

2013

2012

2011

Creative Commons License This work by Mathias Verraes is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 License.