原發表於Takeshi Yu的部落格。
準確的數值計算在企業應用程式中至關重要,尤其是那些涉及財務、會計或庫存的應用程式。 即使很小的捨入誤差也會導致嚴重的問題。 PHP 8.4 增強的 BCMath 物件 API 為精確且有效率的小數計算提供了完善的解決方案。
經驗豐富的 PHP 開發人員熟悉浮點不精確性:
<code class="language-php">$a = 0.1; $b = 0.2; var_dump($a + $b); // Outputs: 0.30000000000000004</code>
這種不準確在金融環境中是不可接受的。 這些小錯誤累積起來,就會導致現實世界的差異。
精確的小數計算從資料庫開始。 DECIMAL
類型是必需的:
<code class="language-php">// In Laravel Migration Schema::create('items', function (Blueprint $table) { $table->id(); $table->decimal('quantity', 10, 3); // Precision: 10 digits, 3 decimal places $table->decimal('price', 10, 3); // Precision: 10 digits, 3 decimal places $table->decimal('discount', 10, 3); // Precision: 10 digits, 3 decimal places $table->decimal('tax', 10, 3); // Precision: 10 digits, 3 decimal places // ... other columns });</code>
DECIMAL
確保:
雖然可能比 FLOAT
稍慢,但精度優勢超過了關鍵任務系統中的效能差異。
Laravel 透過其轉換系統簡化了小數處理:
<code class="language-php">class Item extends Model { protected $casts = [ 'quantity' => 'decimal:3', 'price' => 'decimal:3', 'discount' => 'decimal:3', 'tax' => 'decimal:3', ]; }</code>
但是,請記住 Laravel 鑄造主要管理:
即使使用正確的資料庫類型和 Laravel 轉換,也可能會出現計算錯誤:
<code class="language-php">// Database values $item1 = Item::find(1); // price: "99.99" $item2 = Item::find(2); // price: "149.99" // Calculation without BCMath $subtotal = $item1->price + $item2->price; $tax = $subtotal * 0.05; // 5% tax var_dump($tax); // Outputs: float(12.499000000000002) instead of 12.499</code>
發生這種情況是因為 PHP 在算術過程中隱式將字串轉換為數字:
<code class="language-php">// String values from database $price1 = "99.99"; $price2 = "149.99"; echo gettype($price1); // string // Implicit conversion to float $total = $price1 + $price2; echo gettype($total); // double (float)</code>
傳統的 BCMath 擴展提供了精度:
<code class="language-php">// Database values $item1 = Item::find(1); // price: "99.99" $item2 = Item::find(2); // price: "149.99" // Using BCMath functions $subtotal = bcadd($item1->price, $item2->price, 3); $tax = bcmul($subtotal, $item2->tax, 3); var_dump($tax); // Precisely outputs: string(5) "12.499"</code>
然而,複雜的計算變得冗長且難以維護:
<code class="language-php">// Complex order calculation (using BCMath functions) // ... (code omitted for brevity)</code>
PHP 8.4 物件導向的 BCMath API 簡化了精確計算:
<code class="language-php">use BCMath\Number; $item1 = Item::find(1); $price = new Number($item1->price); $quantity = new Number($item1->quantity); $discountRate = new Number($item1->discount); $taxRate = new Number($item1->tax); // Natural and readable calculations $subtotal = $price * $quantity; $discount = $subtotal * $discountRate; $afterDiscount = $subtotal - $discount; $tax = $afterDiscount * $taxRate; $total = $afterDiscount + $tax; var_dump($total); // Automatically converts to string</code>
新 API 的優點:
Stringable
介面實作。 Laravel 的訪客實現了進一步的優雅:
<code class="language-php">use BCMath\Number; class Item extends Model { // ... (accessor methods for quantity, price, discount, tax using Number) ... }</code>
或使用自訂演員表:
<code class="language-php">// ... (DecimalCast class implementation) ...</code>
然後:
<code class="language-php">$item1 = Item::find(1); $subtotal = $item1->price * $item1->quantity; // ... (rest of the calculation) ...</code>
在醫療保健庫存管理中,精確的小數計算至關重要。 PHP 8.4 的 BCMath 物件 API 與 Laravel 集成,顯著改進了這些計算的處理,提供精度、可讀性、可維護性和類型安全性。 雖然舊的 BCMath 函數達到了其目的,但這種新方法大大簡化了開發。
以上是使用新的 BCMath 物件 API 在 PHP 中處理小數計算的詳細內容。更多資訊請關注PHP中文網其他相關文章!