-
Notifications
You must be signed in to change notification settings - Fork 0
Add PHP 8.4 RoundingMode enum support with polyfill compatibility #35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
b54f7c5
442eb87
150f511
2483d45
33ad191
7e6ccb2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
This file was deleted.
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| <?php | ||
|
|
||
| /** | ||
| * RoundingMode enum polyfill for PHP 8.1-8.3. | ||
| * | ||
| * This enum provides the same interface as PHP 8.4's native RoundingMode enum, | ||
| * but TowardsZero, AwayFromZero, and NegativeInfinity will throw exceptions | ||
| * when used in PHP < 8.4 to maintain compatibility expectations. | ||
| * | ||
| * The enum is only defined if: | ||
| * - PHP version is 8.1 or higher (enum support) | ||
| * - Native RoundingMode enum doesn't already exist (PHP < 8.4) | ||
| */ | ||
| // @phpstan-ignore-next-line | ||
| if (!enum_exists('RoundingMode') && version_compare(PHP_VERSION, '8.1', '>=')) { | ||
| enum RoundingMode: string | ||
| { | ||
| case HalfAwayFromZero = 'half_away_from_zero'; | ||
| case HalfTowardsZero = 'half_towards_zero'; | ||
| case HalfEven = 'half_even'; | ||
| case HalfOdd = 'half_odd'; | ||
| case TowardsZero = 'towards_zero'; | ||
| case AwayFromZero = 'away_from_zero'; | ||
| case NegativeInfinity = 'negative_infinity'; | ||
| } | ||
| } |
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -958,9 +958,13 @@ public static function ceil(string $num): string | |
| /** | ||
| * Round to a given decimal place. | ||
| * | ||
| * @param string $num The value to round | ||
| * @param int $precision The number of decimal digits to round to | ||
| * @param int|\RoundingMode $mode The rounding mode (PHP8.4+ supports RoundingMode enum) | ||
| * | ||
| * @throws \ValueError if inputs are not well-formed | ||
| */ | ||
| public static function round(string $num, int $precision = 0, int $mode = PHP_ROUND_HALF_UP): string | ||
| public static function round(string $num, int $precision = 0, $mode = PHP_ROUND_HALF_UP): string | ||
| { | ||
| self::validateNumberString($num, 'bcround', 1, 'num'); | ||
|
|
||
|
|
@@ -973,6 +977,9 @@ public static function round(string $num, int $precision = 0, int $mode = PHP_RO | |
| return '0'; | ||
| } | ||
|
|
||
| // Convert RoundingMode enum to integer constant for PHP 8.4+ compatibility | ||
| $roundingMode = self::convertRoundingMode($mode); | ||
|
|
||
| // Based on: https://stackoverflow.com/a/1653826 | ||
| if ($precision < 0) { | ||
| // When precision is negative, we round to the left of the decimal point | ||
|
|
@@ -981,13 +988,47 @@ public static function round(string $num, int $precision = 0, int $mode = PHP_RO | |
| $shifted = self::div($num, $factor, 10); // Use a high precision for intermediate calculation | ||
|
|
||
| // Apply rounding | ||
| $rounded = self::bcroundHelper($shifted, 0, $mode); | ||
| $rounded = self::bcroundHelper($shifted, 0, $roundingMode); | ||
|
|
||
| // Shift back | ||
| return self::mul($rounded, $factor, 0); | ||
| } | ||
|
|
||
| return self::bcroundHelper($num, $precision, $mode); | ||
| return self::bcroundHelper($num, $precision, $roundingMode); | ||
| } | ||
|
|
||
| /** | ||
| * Convert RoundingMode enum to integer constant for backward compatibility. | ||
| * | ||
| * @param int|\RoundingMode $mode The rounding mode | ||
| * | ||
| * @return int The corresponding PHP_ROUND_* constant | ||
| * | ||
| * @throws \ValueError If an invalid rounding mode is provided | ||
| */ | ||
| private static function convertRoundingMode($mode): int | ||
| { | ||
| // RoundingMode enum support (both native PHP 8.4+ and polyfill PHP 8.1-8.3) | ||
| if (enum_exists('RoundingMode') && $mode instanceof \RoundingMode) { | ||
| return match ($mode) { | ||
| \RoundingMode::HalfAwayFromZero => PHP_ROUND_HALF_UP, | ||
| \RoundingMode::HalfTowardsZero => PHP_ROUND_HALF_DOWN, | ||
| \RoundingMode::HalfEven => PHP_ROUND_HALF_EVEN, | ||
| \RoundingMode::HalfOdd => PHP_ROUND_HALF_ODD, | ||
| // TODO: Support additional modes if needed | ||
| \RoundingMode::NegativeInfinity => throw new \ValueError('RoundingMode::NegativeInfinity is not supported'), | ||
| \RoundingMode::TowardsZero => throw new \ValueError('RoundingMode::TowardsZero is not supported'), | ||
| \RoundingMode::AwayFromZero => throw new \ValueError('RoundingMode::AwayFromZero is not supported'), // @phpstan-ignore-line | ||
|
Comment on lines
+1023
to
+1025
|
||
| default => throw new \ValueError('Unsupported RoundingMode') | ||
| }; | ||
| } | ||
|
|
||
| // Backward compatibility for PHP_ROUND_* constants | ||
| if (is_int($mode)) { | ||
| return $mode; | ||
| } | ||
|
|
||
| throw new \ValueError('Invalid rounding mode provided'); | ||
| } | ||
|
|
||
| /** | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The PHPStan ignore comment should include a reason for why it's needed. Consider adding a brief explanation like
// @phpstan-ignore-line match.unhandledor similar to clarify why this line needs to be ignored.