brick / money

A money and currency library for PHP
MIT License
1.65k stars 102 forks source link

Feature request: Allow arithmetic operations with differing currencies if one money obj has amount of 0 #84

Open Anticom opened 7 months ago

Anticom commented 7 months ago

Feature Request

IMHO a MoneyMismatchException should not be thrown under certain circumstances when performing arithmetic operations where one Money's amount is exactly zero.

For example:

  1. 123.45 GBP + 0.00 EUR = 123.45 GBP
  2. 10.00 USD - 0.00 JPY = 10.00 USD

Use cases

When building an application that allows products with additional optional services to be purchased, this would allow us to easily default to a zero-value money objects if no additional services where selected by the user and add that to the product's price without having to know the currency of those additional services of whom none where selected.

In my special use-case we're building a multi-tenancy application where the currencies are bound to the tenant object, however the currencies are also supplied by those additional services (if fetched).

Things to consider

It may not be as straight forward to decide what currency to "keep" when adding / substracting zero value money objects. The most intuitive approach would be to keep the currency of the non-zero money, however that may not always yield the result a developer is looking for or expecting in that case.
In order to mitigate this, a special "null" currency could be added accompanied by a dedicated factory method on the Money class, i.e. Money::null(). This way we have to be very explicit about this and the expected currency should be obvious.

Compatibility with current state of brick/money

In case this is implemented transparently by not performing an equality check of the currencies if either of the involved money objects has an amount of zero, this may break someone's code relying on the MoneyMismatchException regardless of the amounts. However when a dedicated null-currency is added, this probably will not change the behavior of current implementation but strictly add new functionality.

Anticom commented 7 months ago

I just noticed there already is a Money::zero() factory function, however it still requires an explicit currency to be given, leaving me with the issue described above.