
Currency and Money Example
The Currency and Money Value Objects are probably the most used examples for explaining Value Objects, thanks to the Money pattern. This design pattern provides a solution for modeling a problem that avoids a floating-point rounding issue, which in turn allows for deterministic calculations to be performed.
In the real world, a currency describes monetary units in the same way that meters and yards describe distance units. Each currency is represented with a three-letter uppercase ISO code:
class Currency
{
private $isoCode;
public function __construct($anIsoCode)
{
$this->setIsoCode($anIsoCode);
}
private function setIsoCode($anIsoCode)
{
if (!preg_match('/^[A-Z]{3}$/', $anIsoCode)) {
throw new InvalidArgumentException();
}
$this->isoCode = $anIsoCode;
}
public function isoCode()
{
return $this->isoCode;
}
}
One of the main goals of Value Objects is also the holy grail of Object-Oriented design: encapsulation. By following this pattern, you'll end up with a dedicated location to put all the validation, comparison logic, and behavior for a given concept.
In the previous code example, we can build a Currency with an AAA Currency ISO code. That isn't valid at all. Write a more specific rule that will check if the ISO Code is valid. A full list of valid currency ISO codes can be found here. If you need help, take a look at the Money packagist library.
Money is used to measure a specific amount of currency. It's modeled using an amount and a currency. Amount, in the case of the Money pattern, is implemented using an integer representation of the Currency's least-valuable fraction — For example in the case of USD or EUR, cents.
As a bonus, you might also notice that we're using self encapsulation to set the ISO code, which centralizes changes in the Value Object itself:
class Money
{
private $amount;
private $currency;
public function __construct($anAmount, Currency $aCurrency)
{
$this->setAmount($anAmount);
$this->setCurrency($aCurrency);
}
private function setAmount($anAmount)
{
$this->amount = (int) $anAmount;
}
private function setCurrency(Currency $aCurrency)
{
$this->currency = $aCurrency;
}
public function amount()
{
return $this->amount;
}
public function currency()
{
return $this->currency;
}
}
Now that you know the formal definition of Value Objects, let's dive deeper into some of the powerful features they offer.