定制 nanasess/bcmath-polyfill 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

nanasess/bcmath-polyfill

Composer 安装命令:

composer require nanasess/bcmath-polyfill

包简介

PHP 8.4 bcmath functions polyfill with fallback compatibility for environments without bcmath extension. Based on phpseclib/bcmath_compat with additional support for new PHP 8.4 bcmath functions.

README 文档

README

PHP 8.4 bcmath functions polyfill with fallback compatibility for environments without bcmath extension.

Software License CI Status PHPStan Level Max Latest Version Total Downloads

🚀 Features

  • ✅ Complete bcmath extension polyfill for PHP 8.1+
  • ✅ Supports all PHP 8.4+ bcmath functions including bcfloor(), bcceil(), bcround(), and bcdivmod()
  • ✅ PHP 8.5 compatibility tested and verified
  • ✅ Zero dependencies in production (uses phpseclib for arbitrary precision math)
  • ✅ Seamless fallback when bcmath extension is not available
  • ✅ 100% compatible with native bcmath functions

📦 Installation

Install via Composer:

composer require nanasess/bcmath-polyfill

🔧 Usage

Simply include the polyfill in your project and use bcmath functions as you normally would:

// The polyfill will automatically load when bcmath extension is not available
require_once 'vendor/autoload.php';

// All bcmath functions work identically to the native extension
echo bcadd('1.234', '5.678', 2);    // 6.91
echo bcmul('2.5', '3.5', 1);        // 8.7
echo bcpow('2', '8');               // 256

// PHP 8.4 functions are also supported
echo bcfloor('4.7');                // 4
echo bcceil('4.3');                 // 5
echo bcround('3.14159', 2);         // 3.14

// bcround() supports RoundingMode enum (PHP 8.1+ with polyfill, native in PHP 8.4+)
echo bcround('2.5', 0, \RoundingMode::HalfAwayFromZero);  // 3
echo bcround('2.5', 0, \RoundingMode::HalfTowardsZero);   // 2
echo bcround('2.5', 0, \RoundingMode::HalfEven);          // 2
echo bcround('2.5', 0, \RoundingMode::HalfOdd);           // 3
echo bcround('2.5', 0, \RoundingMode::TowardsZero);       // 2
echo bcround('2.5', 0, \RoundingMode::AwayFromZero);      // 3
echo bcround('2.5', 0, \RoundingMode::PositiveInfinity);  // 3
echo bcround('2.5', 0, \RoundingMode::NegativeInfinity);  // 2

// bcdivmod() returns [quotient, remainder]
[$quot, $rem] = bcdivmod('17', '5');  // ['3', '2']

📋 Supported Functions

Classic bcmath Functions

  • bcadd() - Add two arbitrary precision numbers
  • bcsub() - Subtract one arbitrary precision number from another
  • bcmul() - Multiply two arbitrary precision numbers
  • bcdiv() - Divide two arbitrary precision numbers
  • bcmod() - Get modulus of an arbitrary precision number
  • bcpow() - Raise an arbitrary precision number to another
  • bcsqrt() - Get the square root of an arbitrary precision number
  • bcscale() - Set/get default scale parameter
  • bccomp() - Compare two arbitrary precision numbers
  • bcpowmod() - Raise an arbitrary precision number to another, reduced by a specified modulus

PHP 8.4 Functions (Added in PR #6)

  • bcfloor() - Round down to the nearest integer
  • bcceil() - Round up to the nearest integer
  • bcround() - Round to a specified precision with configurable rounding modes
  • bcdivmod() - Get the quotient and remainder of a division in a single call

RoundingMode Enum Support

The bcround() function supports PHP 8.4's RoundingMode enum through a polyfill for PHP 8.1-8.3. All eight native modes are implemented with exact, arbitrary-precision string arithmetic (no float fallback), so results match the native bcround() even for very large or high-precision numbers:

  • RoundingMode::HalfAwayFromZero (equivalent to PHP_ROUND_HALF_UP)
  • RoundingMode::HalfTowardsZero (equivalent to PHP_ROUND_HALF_DOWN)
  • RoundingMode::HalfEven (equivalent to PHP_ROUND_HALF_EVEN)
  • RoundingMode::HalfOdd (equivalent to PHP_ROUND_HALF_ODD)
  • RoundingMode::TowardsZero
  • RoundingMode::AwayFromZero
  • RoundingMode::NegativeInfinity
  • RoundingMode::PositiveInfinity

The legacy integer PHP_ROUND_* constants are also accepted for the four half-modes.

Note: The polyfilled RoundingMode is a pure enum, matching native PHP 8.4 (it has no backing value; ->value / from() / tryFrom() are intentionally unavailable).

Interoperability with symfony/polyfill-php84

symfony/polyfill-php84 also declares bcceil(), bcfloor(), bcround() and bcdivmod(), but only when the native bcmath extension is already loaded (its purpose is to backport the new PHP 8.4 functions to older PHP that already has bcmath). This package instead provides the full bcmath API for environments without the extension.

When both packages are installed on an environment that does have the bcmath extension and runs PHP 8.2/8.3, both declare bcceil()/bcfloor()/bcround(); whichever autoloads first wins (the function_exists() guards prevent a fatal redeclaration). This package's rounding is implemented with a native-compatible string algorithm, so the numeric results are identical regardless of which implementation is used. On environments without the extension only this package is active.

⚡ Performance

This polyfill uses phpseclib's BigInteger class for arbitrary precision arithmetic, providing reliable performance for applications that cannot use the native bcmath extension.

Performance Benchmarking

This project includes a comprehensive benchmarking tool to compare the performance of the polyfill against native bcmath functions.

Local Benchmark Execution

# Run benchmark with default settings (10,000 iterations)
composer benchmark
# or
php benchmarks/run-benchmarks.php

# Export results in different formats
php benchmarks/run-benchmarks.php -f json -o results.json
php benchmarks/run-benchmarks.php -f csv -o results.csv
php benchmarks/run-benchmarks.php -f markdown -o BENCHMARK.md

# Show help
php benchmarks/run-benchmarks.php --help

Benchmark Configuration

The benchmark tests include:

  • Basic Operations: Addition, subtraction, multiplication, division with various number sizes
  • Advanced Operations: Power, square root, modulo operations
  • Large Numbers: Operations with 100, 500, and 1000 digit numbers
  • High Precision: Operations with scale values of 20, 50, and 100

Interpreting Results

Typical performance comparison shows:

  • Basic operations: Polyfill is ~100-250x slower than native
  • Large numbers: Performance gap increases with number size (up to ~800x slower)
  • Square root: Interestingly, polyfill can be faster for high-precision operations

Example output:

BCMath Performance Benchmark
========================================
Iterations per test: 10000
Native BCMath: Available

Basic Operations
----------------
  Small numbers (10 digits):
    bcadd      | Native:    1.5ms | Polyfill:  230ms | Ratio: 150x slower
    ...

Summary
========================================
Average performance ratio: 26x
Polyfill is on average 26x slower than native

GitHub Actions Integration

The project includes automated benchmarking workflows:

1. PR Benchmarks (/benchmark command)

Comment /benchmark on any PR to run performance tests:

  • Automatically triggered on PR updates to relevant files
  • Quick mode (1,000 iterations) for fast feedback
  • Results posted as PR comment

2. Merge Benchmarks

Automatically runs when PRs are merged to main:

  • Full benchmark (10,000 iterations)
  • Results posted to the merged PR for reference

3. Manual Benchmarks

Trigger via GitHub Actions UI:

  • Customizable iteration count
  • Multi-PHP version testing (8.1, 8.2, 8.3, 8.4, 8.5)
  • Results saved as artifacts

Performance Considerations

While the polyfill is significantly slower than native bcmath:

  • It provides full functionality when bcmath extension is unavailable
  • Performance is adequate for most applications not requiring intensive calculations
  • Consider using native bcmath for performance-critical applications

⚠️ Known Limitations

Extension Detection

  • extension_loaded('bcmath') will return false when using the polyfill
  • Recommended approach: Don't check for the extension, just use the functions

Configuration Options

  • bcmath.scale INI setting is ignored: When the native bcmath extension is not loaded, PHP does not recognize the bcmath.scale INI setting. This means:
    • ini_get('bcmath.scale') returns false
    • ini_set('bcmath.scale', ...) won't work
    • INI settings in php.ini or PHPT tests are ignored
    • The polyfill defaults to scale 0 when no explicit scale is provided
  • Workaround: Use bcscale() instead to set the scale globally
  • To get the current scale:
    • PHP >= 7.3.0: Use bcscale() without arguments
    • PHP < 7.3.0: Use max(0, strlen(bcadd('0', '0')) - 2)

🔄 Key Differences from phpseclib/bcmath_compat and symfony/polyfill-php84

The three libraries target different goals. phpseclib/bcmath_compat is the classic pre-8.4 polyfill. symfony/polyfill-php84 backports only the new PHP 8.4 functions and activates them only when the native bcmath extension is already loaded. bcmath-polyfill provides the complete bcmath API — including the PHP 8.4 additions — for environments with or without the extension.

Feature phpseclib/bcmath_compat symfony/polyfill-php84 bcmath-polyfill
Classic bc functions (bcadd, bcmul, …) ❌ Not provided
Works without the bcmath extension ❌ Requires the extension
bcfloor() / bcceil() / bcround() ✅ (extension required)
bcdivmod() ✅ (delegates to native bc) ✅ (works without the extension)
RoundingMode enum (all 8 modes)
Arbitrary-precision rounding (no float fallback) ✅ (pure string algorithm) ✅ (pure string algorithm)
RoundingMode is a pure enum (native shape)
Implementation of rounding Pure string digits Pure string digits (phpseclib elsewhere)
Extra dependency phpseclib none phpseclib
PHP 8.2+ deprecations ⚠️ Warnings ✅ Fixed ✅ Fixed
Active maintenance ❌ Limited ✅ Active ✅ Active
CI/CD (PHP versions) GitHub Actions (8.1, 8.2, 8.3) 7.2+ GitHub Actions (8.1, 8.2, 8.3, 8.4, 8.5)

When bcmath-polyfill and symfony/polyfill-php84 are installed together on an environment that has the bcmath extension and runs PHP 8.2/8.3, both declare bcceil()/bcfloor()/bcround() and whichever autoloads first wins (guarded by function_exists(), so no fatal redeclaration). Because this package's rounding uses a native-compatible string algorithm, the results are identical either way. See Interoperability with symfony/polyfill-php84.

Migration from phpseclib/bcmath_compat

Switching is seamless - no code changes required:

# Remove old package
composer remove phpseclib/bcmath_compat

# Install bcmath-polyfill
composer require nanasess/bcmath-polyfill

🧪 Testing

Running PHPUnit Tests

# Install dependencies
composer install

# Run all tests
composer test
# or
vendor/bin/phpunit

# Run tests without bcmath extension
vendor/bin/phpunit --group without-bcmath

Docker-based PHPT Testing

This project includes comprehensive Docker-based testing using official PHP core bcmath tests to ensure 100% compatibility:

# Build Docker test environment (PHP 8.3 by default)
docker build -f Dockerfile.test-without-bcmath -t bcmath-phpt-test .

# Run all PHPT tests
docker run --rm -v $PWD:/app bcmath-phpt-test

# Build and test with specific PHP version
docker build -f Dockerfile.test-without-bcmath --build-arg PHP_VERSION=8.4 -t bcmath-phpt-test:8.4 .
docker run --rm -v $PWD:/app bcmath-phpt-test:8.4

# Skip specific tests (supports exact test name matching)
docker run --rm -v $PWD:/app bcmath-phpt-test --skip bcceil,bcround,bcpowmod

# Run specific test file
docker run --rm -v $PWD:/app bcmath-phpt-test tests/php-src/bcadd.phpt

# Show help
docker run --rm bcmath-phpt-test --help

Available Options

  • --skip TESTS - Comma-separated list of test names to skip (exact matching)
  • --help, -h - Show usage information

Supported PHP Versions

  • PHP 8.1, 8.2, 8.3, 8.4, 8.5

The Docker PHPT tests automatically run on GitHub Actions CI across all supported PHP versions to ensure comprehensive compatibility with the official PHP core bcmath test suite.

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

📄 License

This project is licensed under the MIT License - see the LICENSE.md file for details.

🙏 Credits

This project is a fork of phpseclib/bcmath_compat, originally created by the phpseclib team. We've extended it with PHP 8.4 function support and continue to maintain compatibility with all PHP versions.

Made with ❤️ for the PHP community

nanasess/bcmath-polyfill 适用场景与选型建议

nanasess/bcmath-polyfill 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 87.7k 次下载、GitHub Stars 达 0, 最近一次更新时间为 2025 年 07 月 17 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「math」 「BigInteger」 「bcmath」 「bigdecimal」 「polyfill」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 nanasess/bcmath-polyfill 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 nanasess/bcmath-polyfill 我们能提供哪些服务?
定制开发 / 二次开发

基于 nanasess/bcmath-polyfill 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 87.7k
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 31
  • 依赖项目数: 1
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 6
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2025-07-17