2010-09-29 5 views
27

Necesito agregar, multiplicar y comparar valores de moneda en PHP y necesito estar seguro de que es exacto hasta un centavo.¿La mejor práctica para trabajar con valores de moneda en PHP?

Una forma es almacenar todo en float, usar round antes y después de cada operación y épsilon de máquina mental cuando se compara por igualdad. Muy engorroso.

Otra forma es almacenar todo como centavos en tipos de datos enteros, además de recordar convertir de ida y vuelta cada vez que trabajo con la base de datos (mysql, donde uso el tipo de datos decimales). Inelegante, y muchas trampas de error, imho.

Otra forma es inventar mi propio "tipo de datos", almacenar todos los valores en cadenas ("34.12") y crear mis propias funciones de reemplazo matemático. Esta función convertiría el valor en enteros internamente, hacer el cálculo y dar salida al resultado de nuevo a strings. Sorprendentemente complicado, imho.

Mi pregunta: ¿cuál es la mejor práctica para trabajar con valores de moneda en PHP? Gracias!

Respuesta

5

Déjame responder esto yo mismo. La mejor práctica sería crear una clase de "cantidad de dinero". Esta clase almacena la cantidad internamente como centavos en enteros, y ofrece getters, setters, funciones matemáticas como agregar, restar y comparar. Mucho más limpio.

+3

Esto no es, simplemente, la mejor práctica y muy malo Consejo. Por favor, por supuesto, encapsule las funciones que funcionan con funciones matemáticas de precisión arbitraria, pero por favor no siga los consejos anteriores. La mejor respuesta es por Andrew Dunn. –

3

Actualización 2016:

Un par de años más tarde y es de esperar un poco más prudente;)
Desde esta respuesta todavía recibe la UP- ocasional y por voto me sentí la necesidad de revisar mi respuesta. Absolutamente no aconsejo almacenar 'dinero' como enteros nunca más. La única respuesta verdadera es la de Andrew Dunn: use el tipo DECIMAL de Mysql y encapsule las funciones bc_ * de php en una clase Currency.


Voy a mantener mi respuesta obsoleta aquí por el bien integridad

Siempre se debe trabajar con números enteros. Almacene los valores como ints en su base de datos, utilice ints para hacer cálculos y cuando, y solo cuando, desea imprimirlo, conviértalo a algún formato legible.

De esta manera usted completeley evitar los problemas puntuales, que, general, es un gran problema cuando se trabaja con el dinero flotante;)

Editar: Una cosa que vale la pena mencionar: Usted necesita pensar acerca de la precisión antes de empezar a trabajar de esta manera. Como han señalado otros, puede que necesite trabajar con valores menores que un centavo, por lo que debe hacer su multiplicación/división en consecuencia. (Es decir, la moneda * 1000 para una precisión .001)

+2

MySQL y otros tienen el formato DECIMAL/NUMERIC que está diseñado específicamente para eludir problemas de punto flotante y dar resultados exactos. –

+3

Supuse que era irónico, así que no te voté. Por favor confirme que tenía razón :) – thomasmalt

+1

@Tatu Ulmanen: Claro, Mysql sí. Pero si luego haces algo como prueba de igualdad en php, es posible que obtengas resultados inesperados. –

22

En MySQL v5.0.3, MySQLs DECIMAL de tipo de datos almacena un número decimal exacto, es decir, no una representación de punto flotante incorrecto.

Para manipular correctamente los números de precisión en PHP, utilice el arbitrary precision math functions. Internamente, esta biblioteca manipula cadenas de texto.

La moneda está destinada a almacenarse como un número decimal, puede obtener unidades de dinero menores que centavos. Solo debe redondear cualquier valor al mostrar las cifras, no durante la manipulación o el almacenamiento.

+1

Lo siento pero no te entiendo. No hay ningún tipo de datos decimales en php. Si te refieres a flotar: no puedes probar de manera confiable la igualdad al usarlos. – CruftyCraft

+10

PHP tiene un conjunto de funciones diseñadas específicamente para la manipulación y comparación de números de precisión: http://www.php.net/manual/en/ref.bc.php –

0

Mantenga los valores en centavos y use enteros.Escriba clases o funciones auxiliares para encapsular la visualización en la interfaz de usuario y gestionar los valores en las consultas de la base de datos. Si usa flotador, existe demasiado riesgo de perder un centavo en algún lugar.

Cuestiones relacionadas