Php working with money

Saved searches

Use saved searches to filter your results more quickly

You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session. You switched accounts on another tab or window. Reload to refresh your session.

PHP implementation of Fowler’s Money pattern.

License

moneyphp/money

This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?

Sign In Required

Please sign in to use Codespaces.

Launching GitHub Desktop

If nothing happens, download GitHub Desktop and try again.

Launching GitHub Desktop

If nothing happens, download GitHub Desktop and try again.

Launching Xcode

If nothing happens, download Xcode and try again.

Launching Visual Studio Code

Your codespace will open once ready.

There was a problem preparing your codespace, please try again.

Latest commit

Git stats

Files

Failed to load latest commit information.

README.md

Money PHP

PHP library to make working with money safer, easier, and fun!

«If I had a dime for every time I’ve seen someone use FLOAT to store currency, I’d have $999.997634» — Bill Karwin

In short: You shouldn’t represent monetary values by a float. Wherever you need to represent money, use this Money value object. Since version 3.0 this library uses strings internally in order to support unlimited integers.

 use Money\Money; $fiveEur = Money::EUR(500); $tenEur = $fiveEur->add($fiveEur); list($part1, $part2, $part3) = $tenEur->allocate([1, 1, 1]); assert($part1->equals(Money::EUR(334))); assert($part2->equals(Money::EUR(333))); assert($part3->equals(Money::EUR(333)));

The documentation is available at http://moneyphp.org

This library requires the BCMath PHP extension. There might be additional dependencies for specific feature, e.g. the Swap exchange implementation, check the documentation for more information.

Version 4 requires PHP 8.0. For older version of PHP, use version 3 of this library.

$ composer require moneyphp/money
  • JSON Serialization
  • Big integer support utilizing different, transparent calculation logic upon availability (bcmath, gmp, plain php)
  • Money formatting (including intl formatter)
  • Currency repositories (ISO currencies included)
  • Money exchange (including Swap implementation)

We try to follow BDD and TDD, as such we use both phpspec and phpunit to test this library.

Running the tests in Docker

Money requires a set of dependencies, so you might want to run it in Docker.

First, build the image locally:

$ docker run --rm -it -v $PWD:/app -w /app moneyphp vendor/bin/phpunit --exclude-group segmentation

We would love to see you helping us to make this library better and better. Please keep in mind we do not use suffixes and prefixes in class names, so not CurrenciesInterface , but Currencies . Other than that, Style CI will help you using the same code style as we are using. Please provide tests when creating a PR and clear descriptions of bugs when filing issues.

If you discover any security related issues, please contact us at team@moneyphp.org.

The MIT License (MIT). Please see License File for more information.

This library is heavily inspired by Martin Fowler’s Money pattern. A special remark goes to Mathias Verraes, without his contributions, in code and via his blog, this library would not be where it stands now.

About

PHP implementation of Fowler’s Money pattern.

Источник

How to work with Money in PHP

TL;DR: Store monetary values in value objects for developer convience whilst also helping you develop reusable code that feels natural to OOP and addresses precision issues.

Floating point numbers are problematic as they lack defined precision, as certain most decimal numbers cannot be accurately stored in a binary system due to the way floating point values are implemented using exponents.

This lack of defined precision can lead to difficult bugs. At Viva IT we have worked with numbers since we were founded and have experienced some of these kind of issues.

Traditionally people have stored and calculated monetary as integers as they don’t suffer from the same flaws as floats. As the currency is stored as the fraction denomation of a currency (e.g pence or cent) so £3.14 would be stored as an integer of value 314. In PHP the BC math library is also a viable option, it allows you to perform mathmatic operations on numeric formatted strings. Those these two methods can address precision issues, however they can often lead to obscure and reused code and therefore the potenial for bugs is introduced.

We have recently moved to the library brick/money . This provides a value object for dealing with money values while also calculating and storing other relevant metadata such as currency.

Some advantages of using value objects (not just brick/money ) for money are:

  • It allows you to encapsulate metadata about the money value e.g currency, scale, etc.
  • They improve the readability of your code and provide internalisation by default.
  • They can be used as arguments to your functions to ensure that valid monetary values are passed.
  • They allow you to use promote code reuse in a way that feels natural to OOP.

If you can’t or don’t want to couple parts or any of your system to the brick/money library, then there’s no reason you couldn’t develop your own value object:

 // Perform rounding appropriate to your currency here $this->value = (string)$value; > public function add(Money $other): self < if ($this->currency !== $other->currrency) < throw new InvalidArgumentException('Mismatched currency'); >return new self(bcadd($other->value, $this->value, 4), $this->currency); > public function divide(int $divisor): self < return new self(bcdiv($this->value, $divisor, 10), $this->currency); > //. Add other methods here for other operations you might need such as // multiplication, subtraction, or the ability to convert it into a value for the view. >

Important notes about this implementation are:

  • Rounding has not been implemented in this basic example, you can find some examples of how to do this in a BC Math environment here: at Stack Overflow. Note: Brick will perform this for you automatically.
  • This object is immutable (notice that it returns a new object each time). Immutable operations are recommended for value objects as it means that the objects act like a scalar value, this feels more natural for developers because of the existing mental model of they have of money values. Not implementing this value object as immutable could lead to unexpected changes to values in parts of the system.
  • When dividing values in the example above, I specify a higher precisions as certain divisors could lead to remainders. As BC Math doesn’t round values it just ‘chops down’ numbers that are too long, it’s important to perform rounding that is compatible with the domain of your system!

At some point you may want to store a monetary value in the database using an ORM, at Viva IT we use Doctrine’s ORM for persistance and we brick/money value objects in our entities. This approach will lead to coupling your entities to a third-party value object, of course if this is not an option for your software project feel free to use a custom value object (such as the one above) or if not that is not an option you may want to convert your value objects into string scalar values before persistance.

You can also use Doctrine embeddables, although we opted against this as we would like to natively work with scalars in the database for ETL operations.

Here is a typical example of how we might store Brick Money value objects in a Doctrine entity:

balance = (string)$balance->getAmount(); $this->currency = $balance->getCurrency()->getCurrencyCode(); > public function setBalance(Money $balance): void < $this->balance = (string)$balance->getAmount(); $this->currency = $balance->getCurrency()->getCurrencyCode(); > public function getBalance(): Money < return Money::of($this->balance, $this->currency); > >

In conclusion, a correctly implemented value object (immutable and with the correct rounding for your system) is a great way to deal with monetary values in a reuseable and object-oriented way while also making the project convient to work with for developers. brick/money is a good option for teams who don’t mind coupling their coupling their systems to this third-party library. Although if this coupling is a problem, we would advise teams to implement their own value object.

Kane

As a software engineer at Viva IT, his role at the company is to learn and create quality, well-tested software.

Источник

Читайте также:  Uploading image files in php
Оцените статью