Floating point cannot represent 0.1 exactly, so money arithmetic accumulates error that shows up as a total that is one cent off. The usual response is to round at the end, which hides the drift rather than removing it.
final class Money
{
private $cents;
private $currency;
private function __construct($cents, $currency)
{
$this->cents = $cents;
$this->currency = $currency;
}
public static function fromCents($cents, $currency)
{
return new self($cents, $currency);
}
public function add(Money $other)
{
if ($other->currency !== $this->currency) {
throw new DomainException('Currency mismatch.');
}
return new self($this->cents + $other->cents, $this->currency);
}
}
Storing integer minor units removes the representation problem entirely. The larger win is the currency check: an amount carries its currency, so adding euros to lira throws instead of producing a plausible wrong number. Division is where the remaining care is needed — splitting 100 cents three ways must allocate the leftover somewhere explicit rather than rounding each share.