Money is a value object, not a float

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.