Skip to content

Commit 337e538

Browse files
authored
v3.1: bump php to 8.5 (#3)
* v3.1: bump php to 8.5 * fix cov
1 parent d107304 commit 337e538

9 files changed

Lines changed: 71 additions & 49 deletions

File tree

.github/workflows/ci.yml

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@ jobs:
66
runs-on: ubuntu-latest
77
strategy:
88
matrix:
9-
php-versions: [ '8.4', '8.3', '8.2', '8.1' ]
10-
orchestra-versions: [ '8.0', '9.0', '10.0' ]
9+
php-versions: [ '8.5', '8.4', '8.3', '8.2' ]
10+
orchestra-versions: [ '11.0', '10.0', '9.0' ]
1111
exclude:
12-
- php-versions: 8.1
12+
# Laravel 13 (Testbench 11) requires PHP >= 8.3
13+
- php-versions: 8.2
14+
orchestra-versions: 11.0
15+
# Laravel 11 (Testbench 9) does not support PHP 8.5
16+
- php-versions: 8.5
1317
orchestra-versions: 9.0
14-
- php-versions: 8.1
15-
orchestra-versions: 10.0
1618

1719
steps:
1820
- name: Checkout
@@ -41,6 +43,12 @@ jobs:
4143
- name: Remove Qa / bench libs
4244
run: composer remove "laravel/pint" "brick/math" --dev --no-update
4345

46+
# Laravel 11 (Testbench 9) is EOL and carries unpatched security advisories,
47+
# so composer blocks its install by default. Math still supports it, so
48+
# allow it in CI only (never touches the committed composer.json).
49+
- name: Allow advisory-flagged dependencies (Laravel 11 is EOL)
50+
run: composer config --global policy.advisories.block false
51+
4452
- name: Install Orchestra ${{ matrix.orchestra-versions }}
4553
run: composer require "orchestra/testbench:^${{ matrix.orchestra-versions }}" --dev --no-update
4654

.github/workflows/qa.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ jobs:
1717
- name: Setup PHP
1818
uses: shivammathur/setup-php@v2
1919
with:
20-
php-version: 8.4
20+
php-version: 8.5
2121
extensions: mbstring, dom, fileinfo, gmp, bcmath
2222
coverage: xdebug
2323

@@ -39,7 +39,7 @@ jobs:
3939
run: composer install --no-progress --prefer-dist --optimize-autoloader
4040

4141
- name: Check code style
42-
run: composer fix
42+
run: vendor/bin/pint --ansi --config pint.json --test
4343

4444
- name: PHPStan src
4545
run: composer stan
@@ -51,6 +51,6 @@ jobs:
5151
run: vendor/bin/phpunit --coverage-clover ./coverage.xml
5252

5353
- name: Upload coverage to Codecov
54-
uses: codecov/codecov-action@v4
54+
uses: codecov/codecov-action@v5
5555
with:
5656
token: ${{ secrets.CODECOV_TOKEN }}

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33
.phpstan
44
composer.lock
55
/cov
6+
/.*

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
77

88
## [Unreleased]
99

10+
## [3.1.0] - 2026-07-31
11+
12+
### Changed
13+
14+
- Requires PHP 8.2+ (PHP 8.1 is EOL, pin `3.0.*` to stay on it)
15+
- Tested against PHP 8.5, CI matrix is now PHP 8.2 to 8.5 against Orchestra 9, 10 and 11
16+
- `phpunit/phpunit` `^11.0|^12.0|^13.0`, `orchestra/testbench` `^9.0|^10.0|^11.0`
17+
- QA now actually checks code style (`pint --test`) instead of rewriting it on the runner
18+
1019
## [3.0.0] - 2026-02-08
1120

1221
### Changed

README.md

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ composer require fab2s/math
3232

3333
### Requirements
3434

35-
- PHP 8.1+
35+
- PHP 8.2+
3636
- ext-bcmath (required)
3737
- ext-gmp (optional, faster base conversions, mod, pow and powMod)
3838

@@ -368,48 +368,48 @@ protected $casts = [
368368

369369
## Benchmarks
370370

371-
Compared against [brick/math](https://github.com/brick/math) (PHP 8.4, opcache off, GMP enabled). The **bold** value is the faster one in each row, and _Factor_ shows how many times faster it is.
371+
Compared against [brick/math](https://github.com/brick/math) (PHP 8.5, opcache off, GMP enabled). The **bold** value is the faster one in each row, and _Factor_ shows how many times faster it is.
372372

373373
| Operation | fab2s/math | brick/math | Factor |
374374
|---|---:|---:|---:|
375-
| instantiate int | **0.261μs4.0%)** | 0.301μs (±8.9%) | 1.15x |
376-
| instantiate string | **0.244μs36.6%)** | 0.678μs4.5%) | 2.78x |
377-
| add | **0.632μs9.7%)** | 2.278μs3.0%) | 3.60x |
378-
| add variadic | **1.406μs5.6%)** | 6.653μs (±1.3%) | 4.73x |
379-
| sub | **0.612μs1.7%)** | 2.325μs4.8%) | 3.80x |
380-
| mul | **0.665μs (±2.5%)** | 2.183μs4.9%) | 3.28x |
381-
| div | **0.762μs4.1%)** | 4.664μs3.6%) | 6.12x |
382-
| pow | **0.986μs47.0%)** | 1.416μs45.5%) | 1.44x |
383-
| mod | **0.851μs2.3%)** | 2.851μs42.2%) | 3.35x |
384-
| sqrt | **2.160μs3.6%)** | 4.536μs11.3%) | 2.10x |
385-
| abs | **0.344μs4.0%)** | 0.919μs35.8%) | 2.67x |
386-
| negate | **0.379μs10.5%)** | 1.036μs93.7%) | 2.73x |
387-
| clamp | **0.956μs64.5%)** | 4.325μs32.5%) | 4.53x |
388-
| quotient & remainder | **0.894μs10.7%)** | 2.878μs4.6%) | 3.22x |
389-
| inspection | **1.943μs5.7%)** | 4.672μs3.7%) | 2.40x |
390-
| round | **0.596μs31.8%)** | 3.495μs10.2%) | 5.86x |
391-
| ceil | **0.528μs8.1%)** | 2.965μs39.6%) | 5.62x |
392-
| floor | **0.469μs6.2%)** | 2.504μs4.0%) | 5.34x |
393-
| comparisons | **1.400μs7.5%)** | 6.171μs4.7%) | 4.41x |
394-
| to string | **0.529μs6.6%)** | 0.789μs3.4%) | 1.49x |
395-
| chained workflow | **1.810μs3.2%)** | 8.519μs2.0%) | 4.71x |
396-
| large number ops | **1.792μs5.9%)** | 8.273μs (±1.8%) | 4.62x |
397-
| accumulate 100 additions | **41.182μs3.0%)** | 147.875μs11.8%) | 3.59x |
398-
| base convert to 62 | **1.162μs23.8%)** | 6.888μs5.6%) | 5.93x |
399-
| base convert to 16 | 1.081μs15.3%) | **0.965μs7.6%)** | 0.89x |
400-
| integer mul | **0.937μs11.6%)** | 1.873μs5.3%) | 2.00x |
401-
| integer powmod | **1.263μs10.0%)** | 2.810μs7.9%) | 2.22x |
402-
| create 1000 instances | **301.794μs4.2%)** | 731.200μs2.6%) | 2.42x |
375+
| instantiate int | **0.117μs15.1%)** | 0.134μs (±8.7%) | 1.14x |
376+
| instantiate string | **0.107μs2.4%)** | 0.351μs1.5%) | 3.29x |
377+
| add | **0.343μs0.8%)** | 1.177μs1.7%) | 3.43x |
378+
| add variadic | **0.674μs2.4%)** | 3.261μs (±1.3%) | 4.84x |
379+
| sub | **0.345μs4.7%)** | 1.155μs0.5%) | 3.35x |
380+
| mul | **0.382μs (±2.2%)** | 1.162μs1.6%) | 3.04x |
381+
| div | **0.365μs6.5%)** | 2.055μs5.6%) | 5.63x |
382+
| pow | **0.406μs24.3%)** | 0.728μs0.8%) | 1.79x |
383+
| mod | **0.416μs0.8%)** | 1.270μs7.8%) | 3.06x |
384+
| sqrt | **1.123μs0.9%)** | 1.380μs1.3%) | 1.23x |
385+
| abs | **0.185μs0.6%)** | 0.517μs1.1%) | 2.80x |
386+
| negate | **0.215μs1.8%)** | 0.466μs1.0%) | 2.17x |
387+
| clamp | **0.478μs0.7%)** | 2.117μs5.6%) | 4.43x |
388+
| quotient & remainder | **0.453μs0.9%)** | 1.306μs0.8%) | 2.89x |
389+
| inspection | **1.065μs3.1%)** | 1.460μs2.5%) | 1.37x |
390+
| round | **0.342μs3.3%)** | 1.483μs1.1%) | 4.33x |
391+
| ceil | **0.320μs0.5%)** | 1.298μs3.1%) | 4.06x |
392+
| floor | **0.289μs1.9%)** | 1.174μs1.2%) | 4.06x |
393+
| comparisons | **0.644μs1.5%)** | 2.777μs1.2%) | 4.31x |
394+
| to string | **0.326μs1.6%)** | 0.511μs0.5%) | 1.57x |
395+
| chained workflow | **0.965μs1.2%)** | 3.683μs0.9%) | 3.82x |
396+
| large number ops | **0.903μs1.7%)** | 3.433μs (±1.1%) | 3.80x |
397+
| accumulate 100 additions | **21.421μs1.8%)** | 73.261μs1.2%) | 3.42x |
398+
| base convert to 62 | **0.615μs1.3%)** | 2.580μs1.5%) | 4.19x |
399+
| base convert to 16 | 0.607μs1.3%) | **0.458μs1.9%)** | 0.75x |
400+
| integer mul | **0.424μs1.4%)** | 1.014μs11.0%) | 2.39x |
401+
| integer powmod | **0.551μs0.7%)** | 1.410μs1.3%) | 2.56x |
402+
| create 1000 instances | **127.530μs1.8%)** | 385.754μs1.1%) | 3.02x |
403403

404404
All operations above use immutable `Math` (the default). fab2s/math wins every operation except base-16 conversion, where brick/math delegates to GMP's native hex output. The speed advantage comes from keeping bcmath's C-level string arithmetic as the hot path for decimal operations, while brick/math pays for an extra object-wrapping layer on top of GMP. Integer-only operations (`mod`, `pow`, `powMod`, base conversion) use GMP directly when the extension is available, combining the best of both backends. Realistic workflows like chained calculations or 100-iteration accumulations show a consistent 3-5x advantage, with immutability costing only a lightweight `clone` per operation (two properties: a string and an int).
405405

406406
`MathMutable` eliminates the clone overhead entirely for hot loops:
407407

408408
| Operation | MathMutable | Math (immutable) | brick/math |
409409
|---|---:|---:|---:|
410-
| chained workflow | **1.964μs8.5%)** | 2.294μs5.0%) | 14.149μs3.9%) |
411-
| accumulate 100 | **38.086μs2.0%)** | 41.339μs (±2.5%) | 147.063μs (±0.4%) |
412-
| branch | 2.795μs4.0%) | **2.580μs3.3%)** | 12.885μs20.7%) |
410+
| chained workflow | **1.018μs0.2%)** | 1.189μs3.0%) | 5.352μs1.2%) |
411+
| accumulate 100 | **17.499μs1.1%)** | 20.765μs (±2.3%) | 74.043μs (±0.5%) |
412+
| branch | 1.457μs6.2%) | **1.388μs2.7%)** | 5.596μs1.1%) |
413413

414414
Run benchmarks yourself:
415415

composer.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,17 @@
1919
"MIT"
2020
],
2121
"require" : {
22-
"php": "^8.1",
22+
"php": "^8.2",
2323
"ext-bcmath": "*",
2424
"fab2s/context-exception": "^2.0|^3.0"
2525
},
2626
"require-dev": {
27-
"phpunit/phpunit": "^10.0|^11.0",
28-
"laravel/pint": "^1.11",
29-
"orchestra/testbench": "^8.0|^9.0|^10.0",
27+
"phpunit/phpunit": "^11.0|^12.0|^13.0",
28+
"laravel/pint": "^1.21.2",
29+
"orchestra/testbench": "^9.0|^10.0|^11.0",
3030
"phpstan/phpstan": "^2.1",
31-
"brick/math": "^0.14.7",
32-
"phpbench/phpbench": "^1.4"
31+
"brick/math": "^0.14.7|^0.19.0",
32+
"phpbench/phpbench": "^1.4|^1.7"
3333
},
3434
"autoload": {
3535
"psr-4": {

phpunit.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" backupGlobals="false" bootstrap="vendor/autoload.php" colors="true" processIsolation="false" stopOnFailure="false" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.3/phpunit.xsd" cacheDirectory=".phpunit.cache" backupStaticProperties="false">
2+
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" backupGlobals="false" bootstrap="vendor/autoload.php" colors="true" processIsolation="false" stopOnFailure="false" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/11.5/phpunit.xsd" cacheDirectory=".phpunit.cache" backupStaticProperties="false">
33
<testsuites>
44
<testsuite name="Application Test Suite">
55
<directory>./tests/</directory>

pint.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"preset": "laravel",
3+
"cache-file": ".pint.cache",
34
"rules": {
45
"header_comment": {
56
"header": "This file is part of fab2s/Math.\n(c) Fabrice de Stefanis / https://github.com/fab2s/Math\nThis source file is licensed under the MIT license which you will\nfind in the LICENSE file or at https://opensource.org/licenses/MIT"

src/Math.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ class Math extends MathOpsAbstract implements JsonSerializable, Stringable
2525
public function __construct(string|int|float|Math $number)
2626
{
2727
if (isset(static::$globalPrecision)) {
28-
/* @codeCoverageIgnore */
2928
$this->precision = static::$globalPrecision;
3029
}
3130

@@ -173,4 +172,8 @@ public function jsonSerialize(): string
173172
}
174173

175174
// OMG a dynamic static anti pattern ^^
175+
// runs at file load, before per test coverage collection starts,
176+
// so it can never be reported as covered
177+
// @codeCoverageIgnoreStart
176178
Math::gmpSupport();
179+
// @codeCoverageIgnoreEnd

0 commit comments

Comments
 (0)