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

2018
Topic Event Type Location Date
Advanced Domain-Driven Design DDD Europe workshop Brussels, Paris 2018
Design Heuristics DDD eXchange keynote London April 2018
DDD for Messaging Architectures ExploreDDD workshop Denver Sep 2018
Design Heuristics Kandddinsky talk Berlin Oct 2018
Tactical DDD Kandddinsky workshop Berlin Oct 2018
Past agenda entries...

Blog

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.