yuwuhsien/laravel-bcmath-cast
Eloquent casts for PHP 8.4's BCMath\Number object API. Turn model attributes into arbitrary-precision decimals and do natural operator-based arithmetic—add, subtract, multiply, divide—without bcadd/bcmul boilerplate. Requires PHP 8.4+ and Laravel 12+.
Architecture fit
AsDecimal) with no service provider, config file, migration, container binding, or runtime dependency. It operates purely at the persistence boundary — normalizing on write, hydrating on read — and never intercepts requests, queue jobs, or domain services. This is the lowest-cost integration profile available in the Laravel ecosystem: no bootstrap ordering concerns, no package-discovery interactions, no instrumentation to reconcile.BCMath\Number), not a package-owned class. Domain code receiving these values depends on the PHP runtime, not on yuwuhsien/*. That decouples vendor lock-in from type lock-in and is the most favorable single property in this evaluation: if upstream is abandoned, models still hydrate native objects and only the casts() wiring needs reimplementation (roughly one class).string to Number inside code that no cast declaration makes visible. That invisible type change is the primary architectural coupling to manage.Integration feasibility
composer require plus one line per attribute in casts(). A single engineer completes a pilot in under a day. The cost lives entirely in the audit and boundary work that must surround it, not in installation.FLOAT/DOUBLE columns. The schema audit is a prerequisite deliverable with its own owner and estimate, not a follow-on task. Treating it as incidental is the most likely way this initiative ships effort without shipping value.'price' => 'decimal:2' declarations rather than augmenting them. Mechanical to write, but it changes the return type for every reader of that attribute across the codebase.Technical risk
BCMath\Number is an object: === becomes identity comparison, in_array/array_search without strict flags behave unexpectedly, is_numeric() returns false, string interpolation and number_format() need explicit conversion, and collection sortBy on these attributes needs a comparator. None of this is a package defect — all of it is migration work that is invisible in a diff.set() input validation with what get() can parse back" — exactly the failure mode where a write succeeds and a later read throws or truncates. Assume field semantics are pre-stable relative to our edge cases (precision overflow, empty string, null, scientific notation) and gate acceptance on our own round-trip suite.29.99 arriving in a JSON payload can silently defeat the precision guarantee the package exists to provide. Enforcement belongs in FormRequest validation.SUM() over DECIMAL in MySQL/Postgres and a PHP-side reduction over Number objects can disagree at scale boundaries. Divergence surfaces during a finance reconciliation, not in a test suite.Key questions to resolve before committing
FLOAT/DOUBLE columns hold currency, rate, or quantity values, and who owns converting them?Number attributes survive them intact?BCMath\Number in PHP, or any unresolvable round-trip defect.Stack fit
AsDecimal; counters, IDs, sequence numbers, and analytical aggregates stay native. Without that rule the cast spreads into fields where it adds cost without adding correctness.Migration path
FLOAT/DOUBLE column in correctness-sensitive domains, convert to DECIMAL with explicit precision and scale, and verify existing rows survive without rounding drift. Backfill and verification scripts are part of the deliverable, not cleanup.Number; write Number → read back; assert scale and equality; assert null; assert 0; assert empty string; assert precision overflow fails loudly rather than silently truncating.decimal, numeric, string-aware max), client-side types, CSV/PDF exporters, search index mappings, and any ===/is_numeric/number_format call sites.Compatibility
decimal:2 changes the returned type from string to Number for every read path. Any code doing strict comparison, type juggling, sorting, or implicit string conversion on that attribute is a candidate break and must be enumerated during the pilot, not discovered in production.get() can round-trip.Sequencing
Maintenance
BCMath\Number change in a new PHP minor.Support
=== work?" Answer both once in an ADR plus a short engineering note; otherwise they are re-asked in every code review.Scaling
SUM() over DECIMAL and verify parity against the PHP reduction on a representative dataset.Number attributes survive cache, session, and queue serialization intact; if they do not, define a serialization policy before those models reach a job payload.Failure modes
FLOAT column, making the cast cosmetic.DECIMAL overflow: a value exceeding column precision is silently rounded by the database rather than rejected.Number objects after rollout.BCMath\Number, mitigated by the fork plan.string returns and any code written against Number breaks — so revert must be treated as a coordinated change, not a hotfix.Ramp-up
AsDecimal only where the policy allows; column is DECIMAL with explicit precision/scale; input validated as string-safe; no strict comparison or number_format on the raw attribute; round-trip test present.Recommendation for the TPM Adopt, but as a one-class accelerator with a fork plan, not as a dependency of record. The value is real and bounded; the risk is concentrated in vendor immaturity (mitigable) and in the schema/boundary work (not mitigable by the package). Gate the commitment on the stack gates and the schema audit, run the pilot with the acceptance suite described above, and treat the exit criteria as part of the design rather than an afterthought.
How can I help you explore Laravel packages today?