Hace unos días escribí un artículo sobre cómo trabajar con precios en PHP. En él mencionaba un paquete muy interesante llamado Money\Money que nos soluciona los problemas de redondeo habituales al trabajar con precios.
Instalar el paquete Money/Money
Lo mejor, como siempre, instalar el paquete con Composer y añadirlo a nuestro proyecto:
$ composer require moneyphp/money
Primeros pasos con la clase Money
NOTA: Las monedas se almacenan en céntimos.
Esta es una clase muy fácil de usar. Por ejemplo, para trabajar con euros:
use Money\Money;
$dinerito = new Money(520, new Currency('EUR'));
echo $dinerito->getAmount() . PHP_EOL; // Ojo, nos devuelve el importe en céntimos
echo $dinerito->getCurrency() . PHP_EOL;
O también podemos usar un constructor de euros:
$dinerito = Money::EUR(520);
echo $dinerito->getAmount() . PHP_EOL;
echo $dinerito->getCurrency() . PHP_EOL;
Operaciones con monedas
Tenemos unas cuantas operaciones disponibles con las monedas (suma, resta, multiplicar, dividir, módulo, redondeo, valor absoluto y ratio).
Las operaciones no modifican el objeto original sino que crean uno nuevo:
$dinerito = Money::EUR(520);
$nuevoDinerito = $dinerito->add(Money::EUR(100));
echo $dinerito->getAmount() . PHP_EOL; // Esto sigue siendo 520
echo $nuevoDinerito->getAmount() . PHP_EOL; // Esto incluye el euro que hemos sumado
Mucho cuidado con esto, no te confundas y pienses que $dinerito se ha modificado.
Mostrar el importe de forma «elegante»
Bueno, aquí es donde os voy a perder a la mayoría. Si quieres mostrar el importe no es algo tan fácil como usar el método getAmount() que hemos visto antes. Tienes que hacer ésto:
use Money\Currency;
use Money\Money;
use Money\Currencies\ISOCurrencies;
use Money\Formatter\IntlMoneyFormatter;
$dinerito = Money::EUR(520);
$formateadorDeNumeros = new NumberFormatter('es_ES', NumberFormatter::CURRENCY);
$formateadorDeMonedas = new IntlMoneyFormatter($formateadorDeNumeros, new ISOCurrencies);
echo $formateadorDeMonedas->format($dinerito) . PHP_EOL;
¿A que te estás preguntando por qué lo hacen tan complicado? Pues en realidad así es como se hacen bien las cosas. Están separando lo que es la lógica de operaciones con monedas de la forma de representar monedas.
Y si no te gusta siempre puedes hacer:
echo ( $dinerito->getAmount() / 100 ) . " €";
Y ahora, como siempre, lo mejor es ir a la documentación oficial de Money/Money.