วิธีจัดการกับค่าเงินใน PHP และ MySql


16

ฉันได้รับรหัสมรดกจำนวนมากที่เขียนด้วย PHP บนฐานข้อมูล MySQL สิ่งที่ฉันสังเกตคือแอพพลิเคชั่นใช้doublesสำหรับจัดเก็บและจัดการข้อมูล

ตอนนี้ฉันเจอโพสต์มากมายที่กล่าวถึงวิธีdoubleที่ไม่เหมาะสำหรับการดำเนินงานทางการเงินเนื่องจากข้อผิดพลาดในการปัดเศษ อย่างไรก็ตามฉันยังไม่ได้เจอวิธีแก้ปัญหาที่สมบูรณ์เกี่ยวกับวิธีจัดการค่าเงินในโค้ด PHP และเก็บไว้ในฐานข้อมูล MySQL

มีวิธีปฏิบัติที่ดีที่สุดเมื่อต้องจัดการกับเงินใน PHP โดยเฉพาะหรือไม่?

สิ่งที่ฉันกำลังมองหาคือ:

  1. ข้อมูลควรถูกเก็บไว้ในฐานข้อมูลอย่างไร? ประเภทคอลัมน์? ขนาด?
  2. ข้อมูลควรจะถูกจัดการอย่างไรในการบวกและการลบแบบปกติ การคูณหรือหาร?
  3. เมื่อใดที่ฉันควรปัดเศษค่า การปัดเศษเท่าไหร่ที่ยอมรับได้ถ้ามี?
  4. มีความแตกต่างระหว่างการจัดการกับค่าเงินขนาดใหญ่และค่าต่ำหรือไม่?

หมายเหตุ: มากง่ายโค้ดตัวอย่างของวิธีการที่ฉันอาจพบค่าเงินในชีวิตประจำวัน (กังวลด้านความปลอดภัยต่าง ๆ ถูกละเลยทำให้เข้าใจง่ายแน่นอนในชีวิตจริงฉันไม่เคยจะใช้รหัสของฉันเช่นนี้.)

$a= $_POST['price_in_dollars']; //-->(ex: 25.06) will be read as a string should it be cast to double?
$b= $_POST['discount_rate'];//-->(ex: 0.35) value will always be less than 1
$valueToBeStored= $a * $b; //--> any hint here is welcomed 

$valueFromDatabase= $row['price']; //--> price column in database could be double, decimal,...etc.

$priceToPrint=$valueFromDatabase * 0.25; //again cast needed or not?

ฉันหวังว่าคุณจะใช้โค้ดตัวอย่างนี้เป็นวิธีในการดึงกรณีการใช้งานออกมามากขึ้นและแน่นอนว่าจะไม่ใช้มันอย่างแท้จริง

คำถามโบนัส หากฉันจะใช้ ORM เช่น Doctrine หรือ PROPEL จะใช้เงินในรหัสของฉันแตกต่างกันอย่างไร


1
ฉันไม่รู้ PHP แต่การรู้คำศัพท์มีค่าในสถานการณ์เหล่านี้สำหรับ google-fu คำที่คุณกำลังค้นหาคือ "ความแม่นยำตามอำเภอใจ" ซึ่ง google ตอบสนองด้วยphp.net/manual/en/book.bc.php
Jimmy Hoffa

1
@Jimmy Hoffa: ความแม่นยำโดยทั่วไปไม่ใช่สิ่งที่คุณต้องการสิ่งที่สามารถแสดงและทำงานกับเศษส่วนทศนิยมได้อย่างถูกต้อง แน่นอนว่าคุณพบทั้งสองอย่างรวมกัน แต่เช่นdecimalประเภทใน C # มีความแม่นยำ จำกัด แต่เหมาะสำหรับค่าเงิน
Michael Borgwardt

1
@MichaelBorgwardt ถูกต้องฉันลืมเกี่ยวกับประเภทเหตุผลเพราะหลายภาษาไม่มี โทรดีมาก
จิมมี่ฮอฟฟา

ต้องทำงานมากกับสกุลเงินและรหัสมรดกฉันจะบอกว่าไปเก็บไว้ในจำนวนเต็มและใช้เซ็นต์แทนดอลลาร์ อย่างไรก็ตามระวัง 32 จำนวนเต็มสามารถถือจำนวนเล็กน้อยที่น่าแปลกใจ 4) จำนวนเต็ม 32 บิตสามารถถือจำนวน 21 ล้านเท่านั้นหากไม่ได้ลงนามและใช้เซ็นต์
Pieter B

นอกจากนี้โค้ดตัวอย่างของคุณที่แสดงราคาและส่วนลดที่โพสต์นั้นทำให้ฉันหวาดกลัว หวังว่ามันจะง่ายขึ้น แต่ก็ไม่ได้สะท้อนการใช้งานจริง แต่ตามมูลค่าดูเหมือนว่าคุณเชื่อใจเบราว์เซอร์ที่จะบอกคุณว่าราคาของรายการคือการโพสต์กลับเขตข้อมูลที่ซ่อนอยู่หรือบางอย่าง
Carson63000

คำตอบ:


6

มันค่อนข้างยุ่งยากในการจัดการตัวเลขด้วย PHP / MySQL หากคุณใช้ทศนิยม (10,2) และหมายเลขของคุณยาวขึ้นหรือมีความแม่นยำสูงกว่าก็จะถูกตัดโดยไม่มีข้อผิดพลาด (เว้นแต่คุณจะตั้งโหมดที่เหมาะสมสำหรับเซิร์ฟเวอร์ db ของคุณ)

เพื่อจัดการค่าขนาดใหญ่หรือค่าความแม่นยำสูงคุณสามารถใช้ไลบรารี่เช่นBCMathมันจะช่วยให้คุณสามารถดำเนินการขั้นพื้นฐานกับตัวเลขขนาดใหญ่และรักษาความแม่นยำที่จำเป็น

ฉันไม่แน่ใจว่าคุณจะทำการคำนวณอะไร แต่คุณต้องจำไว้ว่า (0.22 * 0.4576) + (0.78 * 0.4576) จะไม่เท่ากับ 0.4576 หากคุณจะไม่ใช้ความแม่นยำที่เหมาะสมผ่านกระบวนการ

ขนาดสูงสุดของ DECIMAL ใน MySQL คือ 65 ดังนั้นควรมีขนาดเกินพอสำหรับวัตถุประสงค์ใด ๆ หากคุณใช้ประเภทฟิลด์ DECIMAL มันจะถูกส่งกลับเป็นสตริงโดยไม่คำนึงถึงการใช้ ORM หรือเพียงแค่ PDO / mysql (i) ธรรมดา

ข้อมูลควรถูกเก็บไว้ในฐานข้อมูลอย่างไร? ประเภทคอลัมน์? ขนาด?

ทศนิยมด้วยความแม่นยำที่คุณต้องการ หากคุณใช้อัตราแลกเปลี่ยนคุณต้องมีทศนิยมอย่างน้อยสี่ตำแหน่ง

ข้อมูลควรจะถูกจัดการอย่างไรในการบวกและการลบแบบปกติ การคูณหรือหาร?

ใช้ BCMath เพื่อประหยัดด้านและทำไมการใช้floatอาจไม่ใช่ความคิดที่ดี

เมื่อใดที่ฉันควรปัดเศษค่า การปัดเศษเท่าไหร่ที่ยอมรับได้ถ้ามี?

สำหรับค่าเงินที่เป็นทศนิยมสองตำแหน่งปกตินั้นเป็นที่ยอมรับ แต่คุณอาจต้องการมากกว่านี้เช่นหากคุณใช้อัตราแลกเปลี่ยน

มีความแตกต่างระหว่างการจัดการกับค่าเงินขนาดใหญ่และค่าต่ำหรือไม่?

ขึ้นอยู่กับสิ่งที่คุณหมายถึงใหญ่ มีความแตกต่างอย่างแน่นอนระหว่างหมายเลขการจัดการที่มีความแม่นยำสูง


9

วิธีแก้ไขง่ายๆคือเก็บเป็นจำนวนเต็ม 99.99 ถูกจัดเก็บเป็น 9999 หากวิธีนี้ใช้ไม่ได้ (และมีหลายสาเหตุที่ทำให้เป็นตัวเลือกที่ไม่ดี) คุณสามารถใช้ประเภททศนิยม http://dev.mysql.com/doc/refman/5.0/en/precision-math-decimal-changes.htmlทางด้าน mysql ในด้าน php ฉันพบ/programming/3244094/decimal-type-in-phpซึ่งอาจเป็นสิ่งที่คุณเป็น

คำถามโบนัส: ยากที่จะพูด orm กำลังทำงานตามชนิดข้อมูลที่เลือก ฉันจะบอกว่าคุณสามารถทำสิ่งที่เป็นนามธรรมเพื่อช่วย แต่ปัญหาเฉพาะนี้ไม่ได้รับการแก้ไขเพียงแค่ย้ายไปที่ ORM


1
FWIW, Drupal Commerce ใช้เคล็ดลับ 9999 ในการจัดเก็บราคา
Florian Margaine

1
"และมีหลายสาเหตุที่อาจเป็นทางเลือกที่ไม่ดี"คุณช่วยแบ่งปันปัญหากับการฝึกนี้ได้ไหม?
Songo


@MichaelBorgwardt ขอขอบคุณสำหรับข้อมูล, Songo ขอโทษสำหรับความล่าช้าพายุเฮอริเคนพาเราออก :)
Ominus

3

ฉันจะพยายามนำประสบการณ์ของฉันในเรื่องนี้:

สิ่งที่ฉันกำลังมองหาคือ:

ข้อมูลควรถูกเก็บไว้ในฐานข้อมูลอย่างไร? ประเภทคอลัมน์? ขนาด?

ฉันใช้DECIMAL(10,2)mysql โดยไม่มีปัญหา (8 ข้อเสร็จสมบูรณ์และ 2 ทศนิยม == 99.999.999,99 == จำนวนมาก) แต่ขึ้นอยู่กับช่วงเงินที่คุณจะต้องครอบคลุม จำนวนมากควรได้รับการดูแลเป็นพิเศษ (ตัวอย่างเช่นค่า OS max float) ในส่วนทศนิยมฉันใช้ 2 ค่าเพื่อหลีกเลี่ยงการตัดหรือปัดเศษค่า การรับเงินมีอยู่ไม่กี่กรณีที่คุณต้องการทศนิยมมากขึ้น (ในกรณีที่คุณต้องแน่ใจว่าผู้ใช้จะทำงานกับพวกเขาทั้งหมดมิฉะนั้นเป็นข้อมูลที่ไร้ประโยชน์)

ข้อมูลควรจะถูกจัดการอย่างไรในการบวกและการลบแบบปกติ การคูณหรือหาร?

ทำงานกับสกุลเงินเดียวและตารางแลกเปลี่ยน (พร้อมวันที่) วิธีนี้ทำให้คุณมั่นใจได้ว่าคุณจะได้บันทึกจำนวนเงินที่ถูกต้องเสมอ พิเศษ: บันทึกค่าที่สมบูรณ์และสร้างมุมมองที่มีผลการคำนวณ สิ่งนี้จะช่วยให้คุณแก้ไขค่าได้ทันที

เมื่อใดที่ฉันควรปัดเศษค่า การปัดเศษเท่าไหร่ที่ยอมรับได้ถ้ามี?

อีกครั้งขึ้นอยู่กับช่วงเงินของระบบ คิดในแง่ของ KISS เสมอถ้าคุณไม่จำเป็นต้องยุ่งกับการแลกเปลี่ยนสกุลเงิน

มีความแตกต่างระหว่างการจัดการกับค่าเงินขนาดใหญ่และค่าต่ำหรือไม่?

ขึ้นอยู่กับระบบปฏิบัติการและภาษาการเขียนโปรแกรมของคุณคุณต้องตรวจสอบค่าสูงสุดและค่าต่ำสุดเสมอ


ขอบคุณสำหรับคำตอบ แต่ถ้าฉันต้องจัดการบางอย่างเช่น$valueToBeStored= $a * $b;ถ้า$aและ$bทั้งสองอ่านเป็นทศนิยมจากฐานข้อมูลฉันคิดว่าพวกเขาจะถูกโยนdoubleใน PHP ใช่ไหม? จะมีผลต่อตัวเลขหรือไม่
Songo

$a และ $bถูกนำมาจาก db? ดังนั้นในตัวอย่างของฉันคุณไม่จำเป็นต้องเก็บ$valueToBeStoredเพราะคุณจะมีแหล่ง$aและ$bข้อมูลอยู่เสมอ ดังนั้นคุณสามารถใช้ค่าในฟังก์ชันโดยทางโปรแกรมหรือสร้างมุมมอง mysql ด้วยผลลัพธ์คอลัมน์ ด้วยวิธีนี้หากมีการเปลี่ยนแปลงค่าใด ๆ คุณไม่ต้องกังวลกับการแก้ไขหลายสถานที่ (เกิดข้อผิดพลาดได้ง่าย)
Alwin Kesler
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.