nanasess/bcmath-polyfill
Pure-PHP polyfill for PHP's bcmath extension, providing bcadd, bcmul and the rest of the arbitrary-precision math functions when the native extension isn't installed. Drop-in compatibility for libraries and apps that rely on bcmath, with no server configuration changes needed.
Architecture fit — This is a compatibility shim, not a capability addition. It only earns a place in the architecture when there is a hard constraint against installing PHP extensions: locked-down shared hosting, distro-pinned base images you don't own, or a distributed Laravel package/plugin that runs on customer infrastructure you can't inspect. In any environment where the platform team controls the Dockerfile, docker-php-ext-install bcmath (or apt-get install php8.x-bcmath) is one line and strictly dominates this dependency. Classify it as an environmental escape hatch: permitted at the runtime edge, prohibited inside domain/payment code that must remain portable. It offers no framework integration value — no service provider, no config, no facades — so "fit" is purely a question of whether the deployment constraint is real.
Integration feasibility — Technically trivial. Composer install, one autoloaded functions file, matching signatures. The non-trivial part is that the integration point is autoload ordering, not an API call: once loaded, it declares bcadd, bcsub, bcmul, bcdiv, bcmod, bcpow, bcsqrt, bccomp, bcscale (plus PHP 8.4 additions) into the global namespace. That is action-at-a-distance — any package in the graph can silently start resolving to the polyfill. Feasibility is high; governance effort is what makes it expensive.
Technical risk
phpseclib/bcmath_compat. It is effectively an unaudited fork of a widely used shim. Zero dependents means near-zero external scrutiny of the delta.bcadd work" but rounding semantics. PHP 8.4 introduced bcround/bcfloor/bcceil with explicit rounding modes; bcdiv truncation behaviour, bcmod sign handling, negative-zero normalisation, and exception types (ValueError/DivisionByZeroError) are all places a pure-PHP emulation drifts from the C extension. A drift here is a money bug.bcpowmod and any PHP 8.4 object-oriented BcMath\Number surface. Confirm the actual exported symbol set against your consumers rather than trusting the README.ext-bcmath is loaded in any environment where the polyfill also loads, you get a fatal Cannot redeclare or a guarded no-op depending on how the bootstrap is written. The failure is environment-dependent and won't reproduce locally.Key questions
ext-bcmath, and what is the cost of changing that? (Usually: near zero.)ext-bcmath is present — guarded function_exists no-op, or fatal?phpseclib/phpseclib 2.x vs 3.x)? 2.x would be an EOL liability in our SBOM.bcpowmod and the OO BcMath\Number API, or only the nine documented functions?Stack fit — Composer-native, zero Laravel coupling, no service provider to register, no config to publish. It is intentionally invisible, which is both its appeal and its hazard. The correct placement is a root-level require in the application's composer.json (or a dedicated runtime-fallback meta-package) so the platform team owns the decision — never let a feature library pull it in transitively.
Migration path
composer.lock for bcadd|bcsub|bcmul|bcdiv|bcmod|bcpow|bcsqrt|bccomp|bcscale and for packages known to hard-depend on BCMath (moneyphp/money, legacy Magento-derived code, invoicing/tax libraries). Establish the blast radius before adding a global override.ext-bcmath to require in composer.json and to every image you build. This makes the constraint explicit and fails fast at install time rather than drifting into a silent polyfill.composer install --no-dev variant, a fallback image tag, or a conditional bootstrap guarded by extension_loaded('bcmath').Decimal value object (or adopt brick/math, which is pure PHP and needs no bcmath at all) and route new code through it. This gives you a swap-out point and stops the polyfill's global functions becoming your de facto API.Compatibility
phpseclib constraint against what's already resolved.symfony/polyfill-*) and with any config.platform.php setting in composer.json, which can mask whether the extension is truly present during resolution.Sequencing
Maintenance — You are tracking a 2-star, single-maintainer package that follows PHP's own release cadence. Expect to own patches: when PHP 8.5/8.6 ships new BCMath functions, this package is the only thing standing between you and a fatal "undefined function" in the fallback profile. Budget for a vendored fork or a Dependabot-with-human-review policy; do not enable auto-merge on this dependency.
Support — No vendor, no SLA, no issue-triage history to lean on. Internal support load falls entirely on the platform team, and the questions will be of the worst kind: "why did the totals differ between the staging and prod images?" Document the fallback profile explicitly in the runbook and tag the relevant images so on-call can see at a glance whether the polyfill is live.
Scaling — CPU-bound and single-threaded in userland. Horizontal scaling still works, but per-request cost rises on any hot arithmetic path, and batch jobs (invoicing runs, repricing, report generation) are where this bites. Keep the polyfill out of queue workers doing bulk financial recalculation, or move those workers to an image with the extension. Memory also grows faster for large operands; watch for elevated peak usage in long-running workers.
Failure modes (ranked by severity)
extension_loaded(), and smoke-test both profiles in CI.Decimal abstraction and a locked dependency set.Ramp-up — Developer-facing effort is near zero: signatures match, so nobody has to learn an API. The cost is conceptual, not technical — engineers must internalise that a global function may be emulated, that behaviour can differ by deployment target, and that "it works locally" is not evidence here. A one-page ADR plus a lint rule or review checklist item ("no direct bc* calls outside the decimal adapter") is sufficient. Realistic estimate: half a day for the platform engineer who owns the ADR, CI matrix, and benchmark; a short team briefing thereafter. The genuine on-cost is the standing maintenance obligation on a package with 2 stars — that is the line item to weigh against the single docker-php-ext-install bcmath it replaces.
How can I help you explore Laravel packages today?