From 5905857fd2652585989ed03e5a5b0beea89ab18e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Thu, 18 Jul 2024 20:44:30 +0200 Subject: [PATCH] RFC: Add the RoundingMode enum (#14833) see https://wiki.php.net/rfc/correctly_name_the_rounding_mode_and_make_it_an_enum Co-authored-by: Saki Takamachi Co-authored-by: Niels Dossche <7771979+nielsdos@users.noreply.github.com> --- NEWS | 5 + UPGRADING | 27 ++--- ext/bcmath/bcmath.c | 10 +- ext/bcmath/bcmath.stub.php | 2 +- ext/bcmath/bcmath_arginfo.h | 4 +- ext/bcmath/tests/bcround_all.phpt | 104 ++++++++++++++++++ ext/bcmath/tests/bcround_away_from_zero.phpt | 4 +- ext/bcmath/tests/bcround_ceiling.phpt | 4 +- ext/bcmath/tests/bcround_early_return.phpt | 50 +++------ ext/bcmath/tests/bcround_error.phpt | 7 -- ext/bcmath/tests/bcround_floor.phpt | 4 +- ext/bcmath/tests/bcround_half_down.phpt | 4 +- ext/bcmath/tests/bcround_half_even.phpt | 4 +- ext/bcmath/tests/bcround_half_odd.phpt | 4 +- ext/bcmath/tests/bcround_half_up.phpt | 4 +- ext/bcmath/tests/bcround_test_helper.inc | 4 +- ext/bcmath/tests/bcround_toward_zero.phpt | 4 +- ...flectionExtension_getClassNames_basic.phpt | 24 ++-- ext/standard/basic_functions.c | 3 + ext/standard/basic_functions.stub.php | 33 ++---- ext/standard/basic_functions_arginfo.h | 35 +++++- ext/standard/math.c | 38 ++++++- ext/standard/php_math_round_mode.h | 6 + .../tests/math/round_RoundingMode.phpt | 102 +++++++++++++++++ .../round_gh12143_expand-rounding-target.phpt | 16 +-- ext/standard/tests/math/round_modes.phpt | 16 +-- .../math/round_modes_ceiling_and_floor.phpt | 17 ++- .../tests/math/round_modes_zeros.phpt | 16 +-- .../tests/math/round_valid_rounding_mode.phpt | 2 +- 29 files changed, 401 insertions(+), 152 deletions(-) create mode 100644 ext/bcmath/tests/bcround_all.phpt create mode 100644 ext/standard/tests/math/round_RoundingMode.phpt diff --git a/NEWS b/NEWS index a4e00693b90..b820e43925c 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,10 @@ PHP NEWS - Core: . Fix GH-14978 (The xmlreader extension phpize build). (Peter Kokot) +- BCMath: + . Adjust bcround()'s $mode parameter to only accept the RoundingMode + enum. (timwolla, saki) + - DOM: . Fix trampoline leak in xpath callables. (nielsdos) @@ -18,6 +22,7 @@ PHP NEWS - Standard: . Fix references in request_parse_body() options array. (nielsdos) + . Add RoundingMode enum. (timwolla, saki) - XSL: . Fix trampoline leak in xpath callables. (nielsdos) diff --git a/UPGRADING b/UPGRADING index 93654728efa..6e748906059 100644 --- a/UPGRADING +++ b/UPGRADING @@ -344,6 +344,9 @@ PHP 8.4 UPGRADE NOTES . stream_bucket_make_writeable() and stream_bucket_new() will now return a StreamBucket instance instead of an stdClass instance. RFC: https://wiki.php.net/rfc/dedicated_stream_bucket + . Added a new RoundingMode enum with clearer naming and improved discoverability + compared to the PHP_ROUND_* constants. + RFC: https://wiki.php.net/rfc/correctly_name_the_rounding_mode_and_make_it_an_enum - SOAP: . Added support for clark notation for namespaces in class map. @@ -549,23 +552,27 @@ PHP 8.4 UPGRADE NOTES would have resulted in 1.0 instead of the correct result 0.0. Additional inputs might also be affected and result in different outputs compared to earlier PHP versions. - . The default value of the 'cost' option for PASSWORD_BCRYPT for password_hash() - has been increased from '10' to '12'. + . The $mode parameter of the round() function has been widened to RoundingMode|int, + accepting instances of a new RoundingMode enum. - RFC: https://wiki.php.net/rfc/bcrypt_cost_2023 - . Four new modes have been added to the round() function: PHP_ROUND_CEILING, - PHP_ROUND_FLOOR, PHP_ROUND_TOWARD_ZERO, PHP_ROUND_AWAY_FROM_ZERO. + RFC: https://wiki.php.net/rfc/correctly_name_the_rounding_mode_and_make_it_an_enum + . Four new modes have been added to the round() function: RoundingMode::PositiveInfinity, + RoundingMode::NegativeInfinity, RoundingMode::TowardsZero, RoundingMode::AwayFromZero. RFC: https://wiki.php.net/rfc/new_rounding_modes_to_round_function - . debug_zval_dump() now indicates whether an array is packed. . Fixed a bug caused by "pre-rounding" of the round() function. Previously, using "pre-rounding" to treat a value like 0.285 (actually 0.28499999999999998) as a decimal number and round it to 0.29. However, "pre-rounding" incorrectly rounds certain numbers, so this fix removes "pre-rounding" and changes the way numbers are compared, so that the values are correctly rounded as decimal numbers. - . long2ip() now returns string instead of string|false. . The maximum precision that can be handled by round() has been extended by one digit. + . The default value of the 'cost' option for PASSWORD_BCRYPT for password_hash() + has been increased from '10' to '12'. + + RFC: https://wiki.php.net/rfc/bcrypt_cost_2023 + . debug_zval_dump() now indicates whether an array is packed. + . long2ip() now returns string instead of string|false. . output_add_rewrite_var() now uses url_rewriter.hosts instead of session.trans_sid_hosts for selecting hosts that will be rewritten. . highlight_string() now has a return type of string|true instead of string|bool. @@ -809,12 +816,6 @@ PHP 8.4 UPGRADE NOTES . P_SID (NetBSD/FreeBSD only). . P_JAILID (FreeBSD only). -- Standard: - . PHP_ROUND_CEILING. - . PHP_ROUND_FLOOR. - . PHP_ROUND_TOWARD_ZERO. - . PHP_ROUND_AWAY_FROM_ZERO. - - Sockets: . SO_EXCLUSIVEADDRUSE (Windows only). . SOCK_CONN_DGRAM (NetBSD only). diff --git a/ext/bcmath/bcmath.c b/ext/bcmath/bcmath.c index cd73e6feb25..ec1cba2f777 100644 --- a/ext/bcmath/bcmath.c +++ b/ext/bcmath/bcmath.c @@ -696,15 +696,20 @@ PHP_FUNCTION(bcround) zend_string *numstr; zend_long precision = 0; zend_long mode = PHP_ROUND_HALF_UP; + zend_object *mode_object = NULL; bc_num num = NULL, result; ZEND_PARSE_PARAMETERS_START(1, 3) Z_PARAM_STR(numstr) Z_PARAM_OPTIONAL Z_PARAM_LONG(precision) - Z_PARAM_LONG(mode) + Z_PARAM_OBJ_OF_CLASS(mode_object, rounding_mode_ce) ZEND_PARSE_PARAMETERS_END(); + if (mode_object != NULL) { + mode = php_math_round_mode_from_enum(mode_object); + } + switch (mode) { case PHP_ROUND_HALF_UP: case PHP_ROUND_HALF_DOWN: @@ -716,7 +721,8 @@ PHP_FUNCTION(bcround) case PHP_ROUND_AWAY_FROM_ZERO: break; default: - zend_argument_value_error(3, "must be a valid rounding mode (PHP_ROUND_*)"); + /* This is currently unreachable, but might become reachable when new modes are added. */ + zend_argument_value_error(3, "is an unsupported rounding mode"); return; } diff --git a/ext/bcmath/bcmath.stub.php b/ext/bcmath/bcmath.stub.php index 5f5e60d3804..eabc0a1042a 100644 --- a/ext/bcmath/bcmath.stub.php +++ b/ext/bcmath/bcmath.stub.php @@ -37,4 +37,4 @@ function bcfloor(string $num): string {} function bcceil(string $num): string {} /** @refcount 1 */ -function bcround(string $num, int $precision = 0, int $mode = PHP_ROUND_HALF_UP): string {} +function bcround(string $num, int $precision = 0, RoundingMode $mode = RoundingMode::HalfAwayFromZero): string {} diff --git a/ext/bcmath/bcmath_arginfo.h b/ext/bcmath/bcmath_arginfo.h index 91ab4fd1564..c3f01527b2b 100644 --- a/ext/bcmath/bcmath_arginfo.h +++ b/ext/bcmath/bcmath_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: cd3d182e13cb0ca22b27c13a8d0a86c20fde5b76 */ + * Stub hash: 7439a5fca649b8c4df317b0da1416c8fe59faf72 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_bcadd, 0, 2, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, num1, IS_STRING, 0) @@ -52,7 +52,7 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_bcround, 0, 1, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, num, IS_STRING, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, precision, IS_LONG, 0, "0") - ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, mode, IS_LONG, 0, "PHP_ROUND_HALF_UP") + ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, mode, RoundingMode, 0, "RoundingMode::HalfAwayFromZero") ZEND_END_ARG_INFO() ZEND_FUNCTION(bcadd); diff --git a/ext/bcmath/tests/bcround_all.phpt b/ext/bcmath/tests/bcround_all.phpt new file mode 100644 index 00000000000..74d12fd427b --- /dev/null +++ b/ext/bcmath/tests/bcround_all.phpt @@ -0,0 +1,104 @@ +--TEST-- +bcround() function all modes +--EXTENSIONS-- +bcmath +--FILE-- + %s\n", $mode->name, $number, bcround($number, 0, $mode)); + } + } +?> +--EXPECT-- +HalfAwayFromZero : 1.0 -> 1 +HalfAwayFromZero : -1.0 -> -1 +HalfAwayFromZero : 1.2 -> 1 +HalfAwayFromZero : -1.2 -> -1 +HalfAwayFromZero : 1.7 -> 2 +HalfAwayFromZero : -1.7 -> -2 +HalfAwayFromZero : 1.5 -> 2 +HalfAwayFromZero : -1.5 -> -2 +HalfAwayFromZero : 2.5 -> 3 +HalfAwayFromZero : -2.5 -> -3 +HalfTowardsZero : 1.0 -> 1 +HalfTowardsZero : -1.0 -> -1 +HalfTowardsZero : 1.2 -> 1 +HalfTowardsZero : -1.2 -> -1 +HalfTowardsZero : 1.7 -> 2 +HalfTowardsZero : -1.7 -> -2 +HalfTowardsZero : 1.5 -> 1 +HalfTowardsZero : -1.5 -> -1 +HalfTowardsZero : 2.5 -> 2 +HalfTowardsZero : -2.5 -> -2 +HalfEven : 1.0 -> 1 +HalfEven : -1.0 -> -1 +HalfEven : 1.2 -> 1 +HalfEven : -1.2 -> -1 +HalfEven : 1.7 -> 2 +HalfEven : -1.7 -> -2 +HalfEven : 1.5 -> 2 +HalfEven : -1.5 -> -2 +HalfEven : 2.5 -> 2 +HalfEven : -2.5 -> -2 +HalfOdd : 1.0 -> 1 +HalfOdd : -1.0 -> -1 +HalfOdd : 1.2 -> 1 +HalfOdd : -1.2 -> -1 +HalfOdd : 1.7 -> 2 +HalfOdd : -1.7 -> -2 +HalfOdd : 1.5 -> 1 +HalfOdd : -1.5 -> -1 +HalfOdd : 2.5 -> 3 +HalfOdd : -2.5 -> -3 +TowardsZero : 1.0 -> 1 +TowardsZero : -1.0 -> -1 +TowardsZero : 1.2 -> 1 +TowardsZero : -1.2 -> -1 +TowardsZero : 1.7 -> 1 +TowardsZero : -1.7 -> -1 +TowardsZero : 1.5 -> 1 +TowardsZero : -1.5 -> -1 +TowardsZero : 2.5 -> 2 +TowardsZero : -2.5 -> -2 +AwayFromZero : 1.0 -> 1 +AwayFromZero : -1.0 -> -1 +AwayFromZero : 1.2 -> 2 +AwayFromZero : -1.2 -> -2 +AwayFromZero : 1.7 -> 2 +AwayFromZero : -1.7 -> -2 +AwayFromZero : 1.5 -> 2 +AwayFromZero : -1.5 -> -2 +AwayFromZero : 2.5 -> 3 +AwayFromZero : -2.5 -> -3 +NegativeInfinity : 1.0 -> 1 +NegativeInfinity : -1.0 -> -1 +NegativeInfinity : 1.2 -> 1 +NegativeInfinity : -1.2 -> -2 +NegativeInfinity : 1.7 -> 1 +NegativeInfinity : -1.7 -> -2 +NegativeInfinity : 1.5 -> 1 +NegativeInfinity : -1.5 -> -2 +NegativeInfinity : 2.5 -> 2 +NegativeInfinity : -2.5 -> -3 +PositiveInfinity : 1.0 -> 1 +PositiveInfinity : -1.0 -> -1 +PositiveInfinity : 1.2 -> 2 +PositiveInfinity : -1.2 -> -1 +PositiveInfinity : 1.7 -> 2 +PositiveInfinity : -1.7 -> -1 +PositiveInfinity : 1.5 -> 2 +PositiveInfinity : -1.5 -> -1 +PositiveInfinity : 2.5 -> 3 +PositiveInfinity : -2.5 -> -2 diff --git a/ext/bcmath/tests/bcround_away_from_zero.phpt b/ext/bcmath/tests/bcround_away_from_zero.phpt index cfaa1500258..df1a16ac187 100644 --- a/ext/bcmath/tests/bcround_away_from_zero.phpt +++ b/ext/bcmath/tests/bcround_away_from_zero.phpt @@ -1,11 +1,11 @@ --TEST-- -bcround() function PHP_ROUND_AWAY_FROM_ZERO +bcround() function AwayFromZero --EXTENSIONS-- bcmath --FILE-- --EXPECT-- ========== non-boundary value ========== diff --git a/ext/bcmath/tests/bcround_ceiling.phpt b/ext/bcmath/tests/bcround_ceiling.phpt index a3f6b50e1f9..5fd93c26214 100644 --- a/ext/bcmath/tests/bcround_ceiling.phpt +++ b/ext/bcmath/tests/bcround_ceiling.phpt @@ -1,11 +1,11 @@ --TEST-- -bcround() function PHP_ROUND_CEILING +bcround() function PositiveInfinity --EXTENSIONS-- bcmath --FILE-- --EXPECT-- ========== non-boundary value ========== diff --git a/ext/bcmath/tests/bcround_early_return.phpt b/ext/bcmath/tests/bcround_early_return.phpt index 372545a22ff..e1980dd3778 100644 --- a/ext/bcmath/tests/bcround_early_return.phpt +++ b/ext/bcmath/tests/bcround_early_return.phpt @@ -4,15 +4,6 @@ bcround() function with early return bcmath --FILE-- [], - 'PHP_ROUND_HALF_DOWN' => [], - 'PHP_ROUND_HALF_EVEN' => [], - 'PHP_ROUND_HALF_ODD' => [], - 'PHP_ROUND_FLOOR' => [], - 'PHP_ROUND_CEIL' => [], - 'PHP_ROUND_AWAY_FROM_ZERO' => [], - 'PHP_ROUND_TOWARD_ZERO' => [], + RoundingMode::HalfAwayFromZero->name => [], ]; foreach ($early_return_cases as [$num, $precision]) { - $result = str_pad("[{$num}, {$precision}]", 33, ' ', STR_PAD_LEFT) . ' => ' . bcround($num, $precision, PHP_ROUND_HALF_UP) . "\n"; + $result = str_pad("[{$num}, {$precision}]", 33, ' ', STR_PAD_LEFT) . ' => ' . bcround($num, $precision, RoundingMode::HalfAwayFromZero) . "\n"; echo $result; - $results['PHP_ROUND_HALF_UP'][] = $result; + $results[RoundingMode::HalfAwayFromZero->name][] = $result; } echo "\n"; -foreach ($otherModes as $mode) { +foreach (RoundingMode::cases() as $mode) { + $results[$mode->name] = []; foreach ($early_return_cases as [$num, $precision]) { - $result = str_pad("[{$num}, {$precision}]", 33, ' ', STR_PAD_LEFT) . ' => ' . bcround($num, $precision, constant($mode)) . "\n"; - $results[$mode][] = $result; + $result = str_pad("[{$num}, {$precision}]", 33, ' ', STR_PAD_LEFT) . ' => ' . bcround($num, $precision, $mode) . "\n"; + $results[$mode->name][] = $result; } - if ($results['PHP_ROUND_HALF_UP'] === $results[$mode]) { - echo str_pad($mode, 24, ' ', STR_PAD_LEFT) . ": result is same to PHP_ROUND_HALF_UP\n"; + if ($results[RoundingMode::HalfAwayFromZero->name] === $results[$mode->name]) { + echo str_pad($mode->name, 24, ' ', STR_PAD_LEFT) . ": result is same to HalfAwayFromZero\n"; } else { - echo str_pad($mode, 24, ' ', STR_PAD_LEFT) . ": result is not same to PHP_ROUND_HALF_UP, failed\n"; + echo str_pad($mode->name, 24, ' ', STR_PAD_LEFT) . ": result is not same to HalfAwayFromZero, failed\n"; } } ?> @@ -90,10 +75,11 @@ foreach ($otherModes as $mode) { [-0.0, 0] => 0 [-0.0000, 0] => 0 - PHP_ROUND_HALF_DOWN: result is same to PHP_ROUND_HALF_UP - PHP_ROUND_HALF_EVEN: result is same to PHP_ROUND_HALF_UP - PHP_ROUND_HALF_ODD: result is same to PHP_ROUND_HALF_UP - PHP_ROUND_FLOOR: result is same to PHP_ROUND_HALF_UP - PHP_ROUND_CEILING: result is same to PHP_ROUND_HALF_UP -PHP_ROUND_AWAY_FROM_ZERO: result is same to PHP_ROUND_HALF_UP - PHP_ROUND_TOWARD_ZERO: result is same to PHP_ROUND_HALF_UP + HalfAwayFromZero: result is same to HalfAwayFromZero + HalfTowardsZero: result is same to HalfAwayFromZero + HalfEven: result is same to HalfAwayFromZero + HalfOdd: result is same to HalfAwayFromZero + TowardsZero: result is same to HalfAwayFromZero + AwayFromZero: result is same to HalfAwayFromZero + NegativeInfinity: result is same to HalfAwayFromZero + PositiveInfinity: result is same to HalfAwayFromZero diff --git a/ext/bcmath/tests/bcround_error.phpt b/ext/bcmath/tests/bcround_error.phpt index d411763b493..95579a4edf0 100644 --- a/ext/bcmath/tests/bcround_error.phpt +++ b/ext/bcmath/tests/bcround_error.phpt @@ -15,14 +15,7 @@ try { } catch (Throwable $e) { echo $e->getMessage()."\n"; } - -try { - bcround('0.001', 0, 1000); -} catch (Throwable $e) { - echo $e->getMessage()."\n"; -} ?> --EXPECT-- bcround(): Argument #1 ($num) is not well-formed bcround(): Argument #1 ($num) is not well-formed -bcround(): Argument #3 ($mode) must be a valid rounding mode (PHP_ROUND_*) diff --git a/ext/bcmath/tests/bcround_floor.phpt b/ext/bcmath/tests/bcround_floor.phpt index 88d7fcd9dbb..346bc81e86e 100644 --- a/ext/bcmath/tests/bcround_floor.phpt +++ b/ext/bcmath/tests/bcround_floor.phpt @@ -1,11 +1,11 @@ --TEST-- -bcround() function PHP_ROUND_FLOOR +bcround() function NegativeInfinity --EXTENSIONS-- bcmath --FILE-- --EXPECT-- ========== non-boundary value ========== diff --git a/ext/bcmath/tests/bcround_half_down.phpt b/ext/bcmath/tests/bcround_half_down.phpt index 03d35802481..69a2a24ed8c 100644 --- a/ext/bcmath/tests/bcround_half_down.phpt +++ b/ext/bcmath/tests/bcround_half_down.phpt @@ -1,11 +1,11 @@ --TEST-- -bcround() function PHP_ROUND_HALF_DOWN +bcround() function HalfTowardsZero --EXTENSIONS-- bcmath --FILE-- --EXPECT-- ========== non-boundary value ========== diff --git a/ext/bcmath/tests/bcround_half_even.phpt b/ext/bcmath/tests/bcround_half_even.phpt index 955f0e14dcf..1413ca69ce1 100644 --- a/ext/bcmath/tests/bcround_half_even.phpt +++ b/ext/bcmath/tests/bcround_half_even.phpt @@ -1,11 +1,11 @@ --TEST-- -bcround() function PHP_ROUND_HALF_EVEN +bcround() function HalfEven --EXTENSIONS-- bcmath --FILE-- --EXPECT-- ========== non-boundary value ========== diff --git a/ext/bcmath/tests/bcround_half_odd.phpt b/ext/bcmath/tests/bcround_half_odd.phpt index 941da75843f..5207142152e 100644 --- a/ext/bcmath/tests/bcround_half_odd.phpt +++ b/ext/bcmath/tests/bcround_half_odd.phpt @@ -1,11 +1,11 @@ --TEST-- -bcround() function PHP_ROUND_HALF_ODD +bcround() function HalfOdd --EXTENSIONS-- bcmath --FILE-- --EXPECT-- ========== non-boundary value ========== diff --git a/ext/bcmath/tests/bcround_half_up.phpt b/ext/bcmath/tests/bcround_half_up.phpt index 17c02c717e3..52129535f2d 100644 --- a/ext/bcmath/tests/bcround_half_up.phpt +++ b/ext/bcmath/tests/bcround_half_up.phpt @@ -1,11 +1,11 @@ --TEST-- -bcround() function PHP_ROUND_HALF_UP +bcround() function HalfAwayFromZero --EXTENSIONS-- bcmath --FILE-- --EXPECT-- ========== non-boundary value ========== diff --git a/ext/bcmath/tests/bcround_test_helper.inc b/ext/bcmath/tests/bcround_test_helper.inc index c51efc46581..00adf18c529 100644 --- a/ext/bcmath/tests/bcround_test_helper.inc +++ b/ext/bcmath/tests/bcround_test_helper.inc @@ -1,6 +1,6 @@ ", bcround($num, $precision, $mode), "\n"; @@ -8,7 +8,7 @@ function printResult (array $cases, int $mode) echo "\n"; } -function run_round_test(int $mode) +function run_round_test(RoundingMode $mode) { $non_boundary_value_cases = [ ['1.1', 0], diff --git a/ext/bcmath/tests/bcround_toward_zero.phpt b/ext/bcmath/tests/bcround_toward_zero.phpt index e9d0e277efe..2d7275ada95 100644 --- a/ext/bcmath/tests/bcround_toward_zero.phpt +++ b/ext/bcmath/tests/bcround_toward_zero.phpt @@ -1,11 +1,11 @@ --TEST-- -bcround() function PHP_ROUND_TOWARD_ZERO +bcround() function TowardsZero --EXTENSIONS-- bcmath --FILE-- --EXPECT-- ========== non-boundary value ========== diff --git a/ext/reflection/tests/ReflectionExtension_getClassNames_basic.phpt b/ext/reflection/tests/ReflectionExtension_getClassNames_basic.phpt index 5a230936fff..47813255381 100644 --- a/ext/reflection/tests/ReflectionExtension_getClassNames_basic.phpt +++ b/ext/reflection/tests/ReflectionExtension_getClassNames_basic.phpt @@ -5,18 +5,16 @@ Felix De Vliegher --FILE-- getClassNames()); +$classNames = $standard->getClassNames(); +sort($classNames); +foreach ($classNames as $className) { + echo $className, PHP_EOL; +} ?> --EXPECT-- -array(5) { - [0]=> - string(22) "__PHP_Incomplete_Class" - [1]=> - string(14) "AssertionError" - [2]=> - string(15) "php_user_filter" - [3]=> - string(12) "StreamBucket" - [4]=> - string(9) "Directory" -} +AssertionError +Directory +RoundingMode +StreamBucket +__PHP_Incomplete_Class +php_user_filter diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index 1eddb342bcc..7b3494303ca 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -34,6 +34,7 @@ #include "ext/session/php_session.h" #include "zend_exceptions.h" #include "zend_attributes.h" +#include "zend_enum.h" #include "zend_ini.h" #include "zend_operators.h" #include "ext/standard/php_dns.h" @@ -304,6 +305,8 @@ PHP_MINIT_FUNCTION(basic) /* {{{ */ assertion_error_ce = register_class_AssertionError(zend_ce_error); + rounding_mode_ce = register_class_RoundingMode(); + BASIC_MINIT_SUBMODULE(var) BASIC_MINIT_SUBMODULE(file) BASIC_MINIT_SUBMODULE(pack) diff --git a/ext/standard/basic_functions.stub.php b/ext/standard/basic_functions.stub.php index d09fbd5ad32..68cc86e7b1f 100644 --- a/ext/standard/basic_functions.stub.php +++ b/ext/standard/basic_functions.stub.php @@ -375,26 +375,6 @@ const PHP_ROUND_HALF_EVEN = UNKNOWN; * @cvalue PHP_ROUND_HALF_ODD */ const PHP_ROUND_HALF_ODD = UNKNOWN; -/** - * @var int - * @cvalue PHP_ROUND_CEILING - */ -const PHP_ROUND_CEILING = UNKNOWN; -/** - * @var int - * @cvalue PHP_ROUND_FLOOR - */ -const PHP_ROUND_FLOOR = UNKNOWN; -/** - * @var int - * @cvalue PHP_ROUND_TOWARD_ZERO - */ -const PHP_ROUND_TOWARD_ZERO = UNKNOWN; -/** - * @var int - * @cvalue PHP_ROUND_AWAY_FROM_ZERO - */ -const PHP_ROUND_AWAY_FROM_ZERO = UNKNOWN; /* crypt.c */ @@ -3145,8 +3125,19 @@ function ceil(int|float $num): float {} /** @compile-time-eval */ function floor(int|float $num): float {} +enum RoundingMode { + case HalfAwayFromZero; + case HalfTowardsZero; + case HalfEven; + case HalfOdd; + case TowardsZero; + case AwayFromZero; + case NegativeInfinity; + case PositiveInfinity; +} + /** @compile-time-eval */ -function round(int|float $num, int $precision = 0, int $mode = PHP_ROUND_HALF_UP): float {} +function round(int|float $num, int $precision = 0, int|RoundingMode $mode = RoundingMode::HalfAwayFromZero): float {} /** @compile-time-eval */ function sin(float $num): float {} diff --git a/ext/standard/basic_functions_arginfo.h b/ext/standard/basic_functions_arginfo.h index 7421ae7e766..00bc7c5509d 100644 --- a/ext/standard/basic_functions_arginfo.h +++ b/ext/standard/basic_functions_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: e3a7bf1e9f0df3e38f6280f91af70e54ce492a60 */ + * Stub hash: 504f4172ac1d64535719234888400063eb37361b */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_set_time_limit, 0, 1, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, seconds, IS_LONG, 0) @@ -1627,7 +1627,7 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_round, 0, 1, IS_DOUBLE, 0) ZEND_ARG_TYPE_MASK(0, num, MAY_BE_LONG|MAY_BE_DOUBLE, NULL) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, precision, IS_LONG, 0, "0") - ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, mode, IS_LONG, 0, "PHP_ROUND_HALF_UP") + ZEND_ARG_OBJ_TYPE_MASK(0, mode, RoundingMode, MAY_BE_LONG, "RoundingMode::HalfAwayFromZero") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_sin, 0, 1, IS_DOUBLE, 0) @@ -3615,6 +3615,10 @@ static const zend_function_entry class_AssertionError_methods[] = { ZEND_FE_END }; +static const zend_function_entry class_RoundingMode_methods[] = { + ZEND_FE_END +}; + static void register_basic_functions_symbols(int module_number) { REGISTER_LONG_CONSTANT("EXTR_OVERWRITE", PHP_EXTR_OVERWRITE, CONST_PERSISTENT); @@ -3704,10 +3708,6 @@ static void register_basic_functions_symbols(int module_number) REGISTER_LONG_CONSTANT("PHP_ROUND_HALF_DOWN", PHP_ROUND_HALF_DOWN, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PHP_ROUND_HALF_EVEN", PHP_ROUND_HALF_EVEN, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PHP_ROUND_HALF_ODD", PHP_ROUND_HALF_ODD, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("PHP_ROUND_CEILING", PHP_ROUND_CEILING, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("PHP_ROUND_FLOOR", PHP_ROUND_FLOOR, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("PHP_ROUND_TOWARD_ZERO", PHP_ROUND_TOWARD_ZERO, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("PHP_ROUND_AWAY_FROM_ZERO", PHP_ROUND_AWAY_FROM_ZERO, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("CRYPT_SALT_LENGTH", PHP_MAX_SALT_LEN, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("CRYPT_STD_DES", 1, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("CRYPT_EXT_DES", 1, CONST_PERSISTENT); @@ -4197,3 +4197,26 @@ static zend_class_entry *register_class_AssertionError(zend_class_entry *class_e return class_entry; } + +static zend_class_entry *register_class_RoundingMode(void) +{ + zend_class_entry *class_entry = zend_register_internal_enum("RoundingMode", IS_UNDEF, class_RoundingMode_methods); + + zend_enum_add_case_cstr(class_entry, "HalfAwayFromZero", NULL); + + zend_enum_add_case_cstr(class_entry, "HalfTowardsZero", NULL); + + zend_enum_add_case_cstr(class_entry, "HalfEven", NULL); + + zend_enum_add_case_cstr(class_entry, "HalfOdd", NULL); + + zend_enum_add_case_cstr(class_entry, "TowardsZero", NULL); + + zend_enum_add_case_cstr(class_entry, "AwayFromZero", NULL); + + zend_enum_add_case_cstr(class_entry, "NegativeInfinity", NULL); + + zend_enum_add_case_cstr(class_entry, "PositiveInfinity", NULL); + + return class_entry; +} diff --git a/ext/standard/math.c b/ext/standard/math.c index ecf614a6ffc..2d0c8fc09e9 100644 --- a/ext/standard/math.c +++ b/ext/standard/math.c @@ -20,6 +20,7 @@ #include "php.h" #include "php_math.h" #include "zend_bitset.h" +#include "zend_enum.h" #include "zend_exceptions.h" #include "zend_multiply.h" #include "zend_portability.h" @@ -30,6 +31,8 @@ #include "basic_functions.h" +PHPAPI zend_class_entry *rounding_mode_ce; + /* {{{ php_intpow10 Returns pow(10.0, (double)power), uses fast lookup table for exact powers */ static inline double php_intpow10(int power) { @@ -301,6 +304,32 @@ PHP_FUNCTION(floor) } /* }}} */ +int php_math_round_mode_from_enum(zend_object *mode) +{ + zval *case_name = zend_enum_fetch_case_name(mode); + zend_string *mode_name = Z_STR_P(case_name); + + switch (ZSTR_VAL(mode_name)[0] + ZSTR_VAL(mode_name)[4]) { + case 'H' + 'A': + return PHP_ROUND_HALF_UP; + case 'H' + 'T': + return PHP_ROUND_HALF_DOWN; + case 'H' + 'E': + return PHP_ROUND_HALF_EVEN; + case 'H' + 'O': + return PHP_ROUND_HALF_ODD; + case 'T' + 'r': + return PHP_ROUND_TOWARD_ZERO; + case 'A' + 'F': + return PHP_ROUND_AWAY_FROM_ZERO; + case 'N' + 't': + return PHP_ROUND_FLOOR; + case 'P' + 't': + return PHP_ROUND_CEILING; + EMPTY_SWITCH_DEFAULT_CASE(); + } +} + /* {{{ Returns the number rounded to specified precision */ PHP_FUNCTION(round) { @@ -308,12 +337,13 @@ PHP_FUNCTION(round) int places = 0; zend_long precision = 0; zend_long mode = PHP_ROUND_HALF_UP; + zend_object *mode_object = NULL; ZEND_PARSE_PARAMETERS_START(1, 3) Z_PARAM_NUMBER(value) Z_PARAM_OPTIONAL Z_PARAM_LONG(precision) - Z_PARAM_LONG(mode) + Z_PARAM_OBJ_OF_CLASS_OR_LONG(mode_object, rounding_mode_ce, mode) ZEND_PARSE_PARAMETERS_END(); if (ZEND_NUM_ARGS() >= 2) { @@ -324,6 +354,10 @@ PHP_FUNCTION(round) } } + if (mode_object != NULL) { + mode = php_math_round_mode_from_enum(mode_object); + } + switch (mode) { case PHP_ROUND_HALF_UP: case PHP_ROUND_HALF_DOWN: @@ -335,7 +369,7 @@ PHP_FUNCTION(round) case PHP_ROUND_FLOOR: break; default: - zend_argument_value_error(3, "must be a valid rounding mode (PHP_ROUND_*)"); + zend_argument_value_error(3, "must be a valid rounding mode (RoundingMode::*)"); RETURN_THROWS(); } diff --git a/ext/standard/php_math_round_mode.h b/ext/standard/php_math_round_mode.h index d4c11a8312f..11a8e873204 100644 --- a/ext/standard/php_math_round_mode.h +++ b/ext/standard/php_math_round_mode.h @@ -15,6 +15,8 @@ +----------------------------------------------------------------------+ */ +#include "php.h" + /* Define rounding modes (all are round-to-nearest) */ #ifndef PHP_ROUND_HALF_UP #define PHP_ROUND_HALF_UP 0x01 /* Arithmetic rounding, up == away from zero */ @@ -47,3 +49,7 @@ #ifndef PHP_ROUND_AWAY_FROM_ZERO #define PHP_ROUND_AWAY_FROM_ZERO 0x08 #endif + +extern PHPAPI zend_class_entry *rounding_mode_ce; + +int php_math_round_mode_from_enum(zend_object *mode); diff --git a/ext/standard/tests/math/round_RoundingMode.phpt b/ext/standard/tests/math/round_RoundingMode.phpt new file mode 100644 index 00000000000..c07186e0093 --- /dev/null +++ b/ext/standard/tests/math/round_RoundingMode.phpt @@ -0,0 +1,102 @@ +--TEST-- +round(): Test RoundingMode enum. +--FILE-- + %+.17g\n", $mode->name, $number, round($number, 0, $mode)); + } +} +?> +--EXPECT-- +HalfAwayFromZero : +1 -> +1 +HalfAwayFromZero : -1 -> -1 +HalfAwayFromZero : +1.2 -> +1 +HalfAwayFromZero : -1.2 -> -1 +HalfAwayFromZero : +1.7 -> +2 +HalfAwayFromZero : -1.7 -> -2 +HalfAwayFromZero : +1.5 -> +2 +HalfAwayFromZero : -1.5 -> -2 +HalfAwayFromZero : +2.5 -> +3 +HalfAwayFromZero : -2.5 -> -3 +HalfTowardsZero : +1 -> +1 +HalfTowardsZero : -1 -> -1 +HalfTowardsZero : +1.2 -> +1 +HalfTowardsZero : -1.2 -> -1 +HalfTowardsZero : +1.7 -> +2 +HalfTowardsZero : -1.7 -> -2 +HalfTowardsZero : +1.5 -> +1 +HalfTowardsZero : -1.5 -> -1 +HalfTowardsZero : +2.5 -> +2 +HalfTowardsZero : -2.5 -> -2 +HalfEven : +1 -> +1 +HalfEven : -1 -> -1 +HalfEven : +1.2 -> +1 +HalfEven : -1.2 -> -1 +HalfEven : +1.7 -> +2 +HalfEven : -1.7 -> -2 +HalfEven : +1.5 -> +2 +HalfEven : -1.5 -> -2 +HalfEven : +2.5 -> +2 +HalfEven : -2.5 -> -2 +HalfOdd : +1 -> +1 +HalfOdd : -1 -> -1 +HalfOdd : +1.2 -> +1 +HalfOdd : -1.2 -> -1 +HalfOdd : +1.7 -> +2 +HalfOdd : -1.7 -> -2 +HalfOdd : +1.5 -> +1 +HalfOdd : -1.5 -> -1 +HalfOdd : +2.5 -> +3 +HalfOdd : -2.5 -> -3 +TowardsZero : +1 -> +1 +TowardsZero : -1 -> -1 +TowardsZero : +1.2 -> +1 +TowardsZero : -1.2 -> -1 +TowardsZero : +1.7 -> +1 +TowardsZero : -1.7 -> -1 +TowardsZero : +1.5 -> +1 +TowardsZero : -1.5 -> -1 +TowardsZero : +2.5 -> +2 +TowardsZero : -2.5 -> -2 +AwayFromZero : +1 -> +1 +AwayFromZero : -1 -> -1 +AwayFromZero : +1.2 -> +2 +AwayFromZero : -1.2 -> -2 +AwayFromZero : +1.7 -> +2 +AwayFromZero : -1.7 -> -2 +AwayFromZero : +1.5 -> +2 +AwayFromZero : -1.5 -> -2 +AwayFromZero : +2.5 -> +3 +AwayFromZero : -2.5 -> -3 +NegativeInfinity : +1 -> +1 +NegativeInfinity : -1 -> -1 +NegativeInfinity : +1.2 -> +1 +NegativeInfinity : -1.2 -> -2 +NegativeInfinity : +1.7 -> +1 +NegativeInfinity : -1.7 -> -2 +NegativeInfinity : +1.5 -> +1 +NegativeInfinity : -1.5 -> -2 +NegativeInfinity : +2.5 -> +2 +NegativeInfinity : -2.5 -> -3 +PositiveInfinity : +1 -> +1 +PositiveInfinity : -1 -> -1 +PositiveInfinity : +1.2 -> +2 +PositiveInfinity : -1.2 -> -1 +PositiveInfinity : +1.7 -> +2 +PositiveInfinity : -1.7 -> -1 +PositiveInfinity : +1.5 -> +2 +PositiveInfinity : -1.5 -> -1 +PositiveInfinity : +2.5 -> +3 +PositiveInfinity : -2.5 -> -2 diff --git a/ext/standard/tests/math/round_gh12143_expand-rounding-target.phpt b/ext/standard/tests/math/round_gh12143_expand-rounding-target.phpt index 71b3dc34f8f..b96a7ffe3e3 100644 --- a/ext/standard/tests/math/round_gh12143_expand-rounding-target.phpt +++ b/ext/standard/tests/math/round_gh12143_expand-rounding-target.phpt @@ -38,7 +38,7 @@ $testCases = [ [4503599627370495.5, 0], [-4503599627370495.5, 0], ], - 'PHP_ROUND_AWAY_FROM_ZERO' => [ + 'RoundingMode::AwayFromZero' => [ [0.12345678901234560, 16], [-0.12345678901234560, 16], [12345678901234567, -1], @@ -46,7 +46,7 @@ $testCases = [ [4503599627370495.5, 0], [-4503599627370495.5, 0], ], - 'PHP_ROUND_TOWARD_ZERO' => [ + 'RoundingMode::TowardsZero' => [ [0.12345678901234566, 16], [-0.12345678901234566, 16], [12345678901234565, -1], @@ -54,7 +54,7 @@ $testCases = [ [4503599627370495.5, 0], [-4503599627370495.5, 0], ], - 'PHP_ROUND_CEILING' => [ + 'RoundingMode::PositiveInfinity' => [ [0.12345678901234560, 16], [-0.12345678901234560, 16], [12345678901234564, -1], @@ -62,7 +62,7 @@ $testCases = [ [4503599627370495.5, 0], [-4503599627370495.5, 0], ], - 'PHP_ROUND_FLOOR' => [ + 'RoundingMode::NegativeInfinity' => [ [0.12345678901234560, 16], [-0.12345678901234560, 16], [12345678901234564, -1], @@ -113,7 +113,7 @@ float(-12345678901234570) float(4503599627370495) float(-4503599627370495) -========== PHP_ROUND_AWAY_FROM_ZERO ========== +========== RoundingMode::AwayFromZero ========== float(0.1234567890123456) float(-0.1234567890123456) float(12345678901234570) @@ -121,7 +121,7 @@ float(-12345678901234570) float(4503599627370496) float(-4503599627370496) -========== PHP_ROUND_TOWARD_ZERO ========== +========== RoundingMode::TowardsZero ========== float(0.1234567890123456) float(-0.1234567890123456) float(12345678901234560) @@ -129,7 +129,7 @@ float(-12345678901234560) float(4503599627370495) float(-4503599627370495) -========== PHP_ROUND_CEILING ========== +========== RoundingMode::PositiveInfinity ========== float(0.1234567890123456) float(-0.1234567890123456) float(12345678901234570) @@ -137,7 +137,7 @@ float(-12345678901234560) float(4503599627370496) float(-4503599627370495) -========== PHP_ROUND_FLOOR ========== +========== RoundingMode::NegativeInfinity ========== float(0.1234567890123456) float(-0.1234567890123456) float(12345678901234560) diff --git a/ext/standard/tests/math/round_modes.phpt b/ext/standard/tests/math/round_modes.phpt index 06a793211b3..3d27ca6e82b 100644 --- a/ext/standard/tests/math/round_modes.phpt +++ b/ext/standard/tests/math/round_modes.phpt @@ -7,10 +7,10 @@ $modes = [ "PHP_ROUND_HALF_DOWN" => PHP_ROUND_HALF_DOWN, "PHP_ROUND_HALF_EVEN" => PHP_ROUND_HALF_EVEN, "PHP_ROUND_HALF_ODD" => PHP_ROUND_HALF_ODD, - "PHP_ROUND_CEILING" => PHP_ROUND_CEILING, - "PHP_ROUND_FLOOR" => PHP_ROUND_FLOOR, - "PHP_ROUND_TOWARD_ZERO" => PHP_ROUND_TOWARD_ZERO, - "PHP_ROUND_AWAY_FROM_ZERO" => PHP_ROUND_AWAY_FROM_ZERO, + "PositiveInfinity" => RoundingMode::PositiveInfinity, + "NegativeInfinity" => RoundingMode::NegativeInfinity, + "TowardsZero" => RoundingMode::TowardsZero, + "AwayFromZero" => RoundingMode::AwayFromZero, ]; $numbers = [ @@ -455,7 +455,7 @@ mode: PHP_ROUND_HALF_ODD 0.0001 => 0.0001 -0.0001 => -0.0001 -mode: PHP_ROUND_CEILING +mode: PositiveInfinity precision: -1 2.5 => 10 -2.5 => -0 @@ -556,7 +556,7 @@ mode: PHP_ROUND_CEILING 0.0001 => 0.0001 -0.0001 => -0.0001 -mode: PHP_ROUND_FLOOR +mode: NegativeInfinity precision: -1 2.5 => 0 -2.5 => -10 @@ -657,7 +657,7 @@ mode: PHP_ROUND_FLOOR 0.0001 => 0.0001 -0.0001 => -0.0001 -mode: PHP_ROUND_TOWARD_ZERO +mode: TowardsZero precision: -1 2.5 => 0 -2.5 => -0 @@ -758,7 +758,7 @@ mode: PHP_ROUND_TOWARD_ZERO 0.0001 => 0.0001 -0.0001 => -0.0001 -mode: PHP_ROUND_AWAY_FROM_ZERO +mode: AwayFromZero precision: -1 2.5 => 10 -2.5 => -10 diff --git a/ext/standard/tests/math/round_modes_ceiling_and_floor.phpt b/ext/standard/tests/math/round_modes_ceiling_and_floor.phpt index 1b3a34f0f98..46939539090 100644 --- a/ext/standard/tests/math/round_modes_ceiling_and_floor.phpt +++ b/ext/standard/tests/math/round_modes_ceiling_and_floor.phpt @@ -1,10 +1,7 @@ --TEST-- -round() with modes PHP_ROUND_CEILING and PHP_ROUND_FLOOR +round() with modes PositiveInfinity and NegativeInfinity --FILE-- --EXPECT-- -mode PHP_ROUND_CEILING +mode PositiveInfinity bool(true) bool(true) bool(true) @@ -52,7 +49,7 @@ bool(true) bool(true) bool(true) -mode PHP_ROUND_FLOOR +mode NegativeInfinity bool(true) bool(true) bool(true) diff --git a/ext/standard/tests/math/round_modes_zeros.phpt b/ext/standard/tests/math/round_modes_zeros.phpt index cdf97395dd9..ee972e54a11 100644 --- a/ext/standard/tests/math/round_modes_zeros.phpt +++ b/ext/standard/tests/math/round_modes_zeros.phpt @@ -7,10 +7,10 @@ $modes = [ "PHP_ROUND_HALF_DOWN" => PHP_ROUND_HALF_DOWN, "PHP_ROUND_HALF_EVEN" => PHP_ROUND_HALF_EVEN, "PHP_ROUND_HALF_ODD" => PHP_ROUND_HALF_ODD, - "PHP_ROUND_CEILING" => PHP_ROUND_CEILING, - "PHP_ROUND_FLOOR" => PHP_ROUND_FLOOR, - "PHP_ROUND_TOWARD_ZERO" => PHP_ROUND_TOWARD_ZERO, - "PHP_ROUND_AWAY_FROM_ZERO" => PHP_ROUND_AWAY_FROM_ZERO, + "PositiveInfinity" => RoundingMode::PositiveInfinity, + "NegativeInfinity" => RoundingMode::NegativeInfinity, + "TowardsZero" => RoundingMode::TowardsZero, + "AwayFromZero" => RoundingMode::AwayFromZero, ]; $precisions = [-1, 0, 1, 2]; @@ -129,7 +129,7 @@ mode: PHP_ROUND_HALF_ODD 0.0 => 0 -0.0 => -0 -mode: PHP_ROUND_CEILING +mode: PositiveInfinity precision: -1 0 => 0 -0 => 0 @@ -154,7 +154,7 @@ mode: PHP_ROUND_CEILING 0.0 => 0 -0.0 => -0 -mode: PHP_ROUND_FLOOR +mode: NegativeInfinity precision: -1 0 => 0 -0 => 0 @@ -179,7 +179,7 @@ mode: PHP_ROUND_FLOOR 0.0 => 0 -0.0 => -0 -mode: PHP_ROUND_TOWARD_ZERO +mode: TowardsZero precision: -1 0 => 0 -0 => 0 @@ -204,7 +204,7 @@ mode: PHP_ROUND_TOWARD_ZERO 0.0 => 0 -0.0 => -0 -mode: PHP_ROUND_AWAY_FROM_ZERO +mode: AwayFromZero precision: -1 0 => 0 -0 => 0 diff --git a/ext/standard/tests/math/round_valid_rounding_mode.phpt b/ext/standard/tests/math/round_valid_rounding_mode.phpt index d61bc6356e1..d7e4655a298 100644 --- a/ext/standard/tests/math/round_valid_rounding_mode.phpt +++ b/ext/standard/tests/math/round_valid_rounding_mode.phpt @@ -9,4 +9,4 @@ try { } ?> --EXPECT-- -round(): Argument #3 ($mode) must be a valid rounding mode (PHP_ROUND_*) +round(): Argument #3 ($mode) must be a valid rounding mode (RoundingMode::*)