moneyphp/money
moneyphp/money is a PHP value-object library for safe money handling without floats. Uses string-based big integers, supports arithmetic, allocation, currencies/ISO repositories, formatting (incl. intl), JSON serialization, and exchange rates. Requires BCMath.
moneyphp/money package is a near-perfect fit for financial systems, e-commerce, billing, or any domain requiring precise monetary calculations. It enforces Martin Fowler’s Money Pattern, ensuring immutability, type safety, and currency-aware operations—critical for domains where floating-point errors or incorrect currency handling could lead to financial discrepancies.Money objects as JSON in database columns (via json type or Money::jsonSerialize()).Money objects directly in JSON APIs (native support via jsonSerialize).min:1000 for EUR).payments service). Its PSR-compliant nature (e.g., jsonSerialize) ensures seamless interoperability with other PHP libraries.composer require moneyphp/money).ISOCurrencies, CryptoCurrencies).Money facade to simplify usage (e.g., Money::EUR(1000)->add($fee)).Money objects as JSON (PostgreSQL, MySQL 8.0+) or decimal strings (e.g., "1000.00" in a decimal(10,2) column).Money objects and database values.FormRequest to validate monetary inputs (e.g., rule('amount')->money()).Money objects for APIs using DecimalMoneyFormatter or IntlLocalizedDecimalFormatter.| Risk Area | Mitigation Strategy |
|---|---|
| BCMath Dependency | Ensure PHP’s bcmath extension is enabled (required for high-precision calculations). Fallback to gmp if bcmath is unavailable. |
| Floating-Point Rejection | Enforce string-based arithmetic (e.g., sprintf('%.2f', $float)) to avoid precision loss. Document this requirement in API contracts. |
| Currency Mismatches | Implement runtime checks (e.g., Money::isSameCurrency()) and fail fast with descriptive errors. |
| Legacy Float Usage | Use Teller (v4.2+) for legacy systems requiring float compatibility (deprecated in v4+). |
| Performance | Benchmark critical paths (e.g., Money::add() in bulk operations). Consider caching Currency objects if used frequently. |
| Testing Complexity | Leverage Money\Comparator for unit tests to assert monetary equality without floating-point quirks. |
moneyphp/crypto-currencies).bcmath vs. gmp).Teller for gradual replacement).FixedExchange or Exchanger.Money objects be persisted? Options:
amount DECIMAL(10,2) + currency VARCHAR(3)).€1,000.00 vs. 1,000.00€) required? This impacts the choice between DecimalMoneyFormatter and IntlLocalizedDecimalFormatter.Money::allocate())? Consider thread-safe patterns or database-level locks.Money objects and database values.
// Model: Order.php
protected $casts = [
'amount' => Money::class, // Automatically serialize/deserialize
];
use Illuminate\Validation\Rule;
Rule::macro('money', function ($attribute, $value, $parameters) {
return Money::parse($value, 'USD')->isValid();
});
Money objects in responses using DecimalMoneyFormatter.
// App\Http\Resources\OrderResource.php
public function toArray($request) {
return [
'amount' => $this->whenLoaded('amount', fn () =>
DecimalMoneyFormatter::format($this->amount)
),
];
}
Money objects in delayed jobs (e.g., RefundJob) using json_encode().Money::parse().ISOCurrencies) if loaded frequently.Cache::remember()).| Phase | Action | Tools/Libraries |
|---|---|---|
| Assessment | Audit existing money-handling code for float usage, currency mismatches, and precision issues. | PHPStan, Psalm, custom linting rules. |
| Pilot | Replace a non-critical module (e.g., a reporting feature) with Money. |
Feature flags, Laravel’s config. |
| Core Integration | Migrate Eloquent models, API endpoints, and validation logic. | Eloquent casts, API resources. |
| Legacy Wrap | Use Teller to wrap legacy float-based systems until fully migrated. |
Money\Teller (v4.2+). |
| Testing | Rewrite unit/integration tests to use Money\Comparator for assertions. |
PHPUnit, Pest. |
| Performance | Benchmark critical paths (e.g., bulk Money::add() operations) and optimize if needed. |
Laravel Forge, Blackfire. |
| Component | Compatibility Notes |
|---|---|
| PHP 8.0+ | Required (v4.0+). Use v3.x for PHP 7.4–8.0 support. |
| Laravel 9/10 | Full compatibility. Laravel’s type system works seamlessly with Money’s immutable objects. |
| Databases | - PostgreSQL: Use jsonb or decimal columns. |
- MySQL 8.0+: Use JSON or DECIMAL columns. |
|
- SQLite: Use JSON or TEXT (store as string, e.g., "1000.00"). |
|
| Third-Party APIs | - Stripe/PayPal: Convert their float-based responses to Money using Money::parse(). |
- GraphQL: Use Laravel GraphQL to serialize Money objects. |
|
| Legacy Systems | - Float-based: Use Teller for gradual migration. |
- Doctrine ORM: Update entity mappings if using Currency embeddables (note v3.0’s code rename). |
How can I help you explore Laravel packages today?