diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index e2e5395f78..3519835579 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -2884,7 +2884,13 @@ parameters: path: src/Controllers/Server/Status/StatusController.php - - message: '#^Parameter \#1 \$value of static method PhpMyAdmin\\Util\:\:formatNumber\(\) expects float\|int\|string, mixed given\.$#' + message: '#^Parameter \#1 \$value of static method PhpMyAdmin\\Util\:\:formatNumber\(\) expects float\|int\|numeric\-string, float\|int\|string given\.$#' + identifier: argument.type + count: 4 + path: src/Controllers/Server/Status/StatusController.php + + - + message: '#^Parameter \#1 \$value of static method PhpMyAdmin\\Util\:\:formatNumber\(\) expects float\|int\|numeric\-string, mixed given\.$#' identifier: argument.type count: 5 path: src/Controllers/Server/Status/StatusController.php @@ -6058,7 +6064,7 @@ parameters: path: src/Engines/Innodb.php - - message: '#^Parameter \#1 \$value of static method PhpMyAdmin\\Util\:\:formatNumber\(\) expects float\|int\|string, mixed given\.$#' + message: '#^Parameter \#1 \$value of static method PhpMyAdmin\\Util\:\:formatNumber\(\) expects float\|int\|numeric\-string, mixed given\.$#' identifier: argument.type count: 11 path: src/Engines/Innodb.php @@ -13888,7 +13894,7 @@ parameters: path: src/StorageEngine.php - - message: '#^Parameter \#1 \$value of static method PhpMyAdmin\\Util\:\:formatNumber\(\) expects float\|int\|string, mixed given\.$#' + message: '#^Parameter \#1 \$value of static method PhpMyAdmin\\Util\:\:formatNumber\(\) expects float\|int\|numeric\-string, mixed given\.$#' identifier: argument.type count: 1 path: src/StorageEngine.php @@ -15012,18 +15018,6 @@ parameters: count: 1 path: src/Util.php - - - message: '#^Loose comparison via "\!\=" is not allowed\.$#' - identifier: notEqual.notAllowed - count: 2 - path: src/Util.php - - - - message: '#^Loose comparison via "\=\=" is not allowed\.$#' - identifier: equal.notAllowed - count: 3 - path: src/Util.php - - message: '#^Method PhpMyAdmin\\Util\:\:getDbInfo\(\) return type has no value type specified in iterable type array\.$#' identifier: missingType.iterableValue @@ -16888,7 +16882,7 @@ parameters: path: tests/unit/Controllers/Server/Status/QueriesControllerTest.php - - message: '#^Parameter \#1 \$value of static method PhpMyAdmin\\Util\:\:formatNumber\(\) expects float\|int\|string, mixed given\.$#' + message: '#^Parameter \#1 \$value of static method PhpMyAdmin\\Util\:\:formatNumber\(\) expects float\|int\|numeric\-string, mixed given\.$#' identifier: argument.type count: 1 path: tests/unit/Controllers/Server/Status/QueriesControllerTest.php diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 0758571314..e7c301345b 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -1925,6 +1925,12 @@ + + data->status['Aborted_clients']]]> + data->status['Aborted_connects']]]> + data->status['Connections']]]> + data->status['Max_used_connections']]]> + data->status['Aborted_clients']]]> data->status['Aborted_clients']]]> @@ -9256,6 +9262,10 @@ + + + + @@ -9275,9 +9285,6 @@ - - - @@ -9296,12 +9303,9 @@ - - - diff --git a/src/Util.php b/src/Util.php index 01b19a9418..e577cc621a 100644 --- a/src/Util.php +++ b/src/Util.php @@ -47,6 +47,7 @@ use function is_object; use function is_scalar; use function is_string; use function log10; +use function max; use function mb_detect_encoding; use function mb_strlen; use function mb_strpos; @@ -365,11 +366,11 @@ class Util * echo formatNumber(0, 6); // 0 * * - * @param float|int|string $value the value to format - * @param int $digitsLeft number of digits left of the comma - * @param int $digitsRight number of digits right of the comma - * @param bool $onlyDown do not reformat numbers below 1 - * @param bool $noTrailingZero removes trailing zeros right of the comma (default: true) + * @param float|int|numeric-string $value the value to format + * @param int $digitsLeft number of digits left of the comma + * @param int $digitsRight number of digits right of the comma + * @param bool $onlyDown do not reformat numbers below 1 + * @param bool $noTrailingZero removes trailing zeros right of the comma (default: true) * * @return string the formatted value and its unit */ @@ -381,51 +382,26 @@ class Util bool $onlyDown = false, bool $noTrailingZero = true, ): string { - if ($value == 0) { + $value = (float) $value; + if ($value === 0.0) { return '0'; } - if (is_string($value)) { - $value = (float) $value; - } - /* l10n: Decimal separator */ $decimalSep = __('.'); /* l10n: Thousands separator */ $thousandsSep = __(','); - $originalValue = $value; //number_format is not multibyte safe, str_replace is safe if ($digitsLeft === 0) { - $value = number_format((float) $value, $digitsRight, $decimalSep, $thousandsSep); - if ($originalValue != 0 && (float) $value == 0) { - return ' <' . number_format((1 / 10 ** $digitsRight), $digitsRight, $decimalSep, $thousandsSep); + $value = number_format($value, $digitsRight, $decimalSep, $thousandsSep); + if ((float) $value === 0.0) { + return '<' . number_format((1 / 10 ** $digitsRight), $digitsRight, $decimalSep, $thousandsSep); } return $value; } - // this units needs no translation, ISO - $units = [ - -8 => 'y', - -7 => 'z', - -6 => 'a', - -5 => 'f', - -4 => 'p', - -3 => 'n', - -2 => 'µ', - -1 => 'm', - 0 => ' ', - 1 => 'k', - 2 => 'M', - 3 => 'G', - 4 => 'T', - 5 => 'P', - 6 => 'E', - 7 => 'Z', - 8 => 'Y', - ]; - // check for negative value to retain sign if ($value < 0) { $sign = '-'; @@ -437,9 +413,9 @@ class Util $dh = 10 ** $digitsRight; // This gives us the right SI prefix already, but $digits_left parameter not incorporated - $d = floor(log10((float) $value) / 3); + $d = floor(log10($value) / 3); // Lowering the SI prefix by 1 gives us an additional 3 zeros - // So if we have 3,6,9,12.. free digits ($digits_left - $cur_digits) to use, then lower the SI prefix + // So if we have 3,6,9,12... free digits ($digits_left - $cur_digits) to use, then lower the SI prefix $curDigits = floor(log10($value / 1000 ** $d) + 1); if ($digitsLeft > $curDigits) { $d -= floor(($digitsLeft - $curDigits) / 3); @@ -449,6 +425,32 @@ class Util $d = 0; } + // SI unit prefixes need no translation + $units = [ + -10 => 'q', // quecto + -9 => 'r', // ronto + -8 => 'y', // yocto + -7 => 'z', // zepto + -6 => 'a', // atto + -5 => 'f', // femto + -4 => 'p', // pico + -3 => 'n', // nano + -2 => 'µ', // micro + -1 => 'm', // milli + 0 => '', + 1 => 'k', // kilo + 2 => 'M', // mega + 3 => 'G', // giga + 4 => 'T', // tera + 5 => 'P', // peta + 6 => 'E', // exa + 7 => 'Z', // zetta + 8 => 'Y', // yotta + 9 => 'R', // ronna + 10 => 'Q', // quetta + ]; + + $d = min(max((int) $d, -10), 10); $value = round($value / (1000 ** $d / $dh)) / $dh; $unit = $units[$d]; @@ -459,11 +461,13 @@ class Util $formattedValue = preg_replace('/' . preg_quote($decimalSep, '/') . '?0+$/', '', $formattedValue); } - if ($originalValue != 0 && $value == 0) { - return ' <' . number_format(1 / 10 ** $digitsRight, $digitsRight, $decimalSep, $thousandsSep) . ' ' . $unit; + if ($value === 0.0) { + return '<' + . number_format(1 / 10 ** $digitsRight, $digitsRight, $decimalSep, $thousandsSep) + . ($unit === '' ? '' : ' ' . $unit); } - return $sign . $formattedValue . ' ' . $unit; + return $sign . $formattedValue . ($unit === '' ? '' : ' ' . $unit); } /** diff --git a/tests/unit/Engines/InnodbTest.php b/tests/unit/Engines/InnodbTest.php index b1a66c4bdd..a7a6b927a9 100644 --- a/tests/unit/Engines/InnodbTest.php +++ b/tests/unit/Engines/InnodbTest.php @@ -194,7 +194,7 @@ class InnodbTest extends AbstractTestCase ' ' . "\n" . ' ' . "\n" . ' Read misses in %' . "\n" . - ' 50 %' . "\n" . + ' 50 %' . "\n" . '' . "\n" . ' ' . "\n" . ' ' . "\n" . diff --git a/tests/unit/UtilTest.php b/tests/unit/UtilTest.php index ab9f887326..396f75e515 100644 --- a/tests/unit/UtilTest.php +++ b/tests/unit/UtilTest.php @@ -538,7 +538,7 @@ class UtilTest extends AbstractTestCase ]; } - /** @psalm-param list{0: float|int|string, 1?: int, 2?: int, 3?: bool, 4?: bool} $arguments */ + /** @psalm-param list{0: float|int|numeric-string, 1?: int, 2?: int, 3?: bool, 4?: bool} $arguments */ #[DataProvider('providerFormatNumber')] public function testFormatNumber(string $expected, array $arguments): void { @@ -594,16 +594,16 @@ class UtilTest extends AbstractTestCase } } - /** @psalm-return array */ + /** @psalm-return array */ public static function providerFormatNumber(): array { return [ - ['10 ', [10, 2, 2]], - ['100 ', [100, 2, 0]], - ['100 ', [100, 2, 2]], - ['100 ', ['100', 2, 2]], - ['-1,000.45 ', [-1000.454, 4, 2]], - ['-1,000.45 ', ['-1000.454', 4, 2]], + ['10', [10, 2, 2]], + ['100', [100, 2, 0]], + ['100', [100, 2, 2]], + ['100', ['100', 2, 2]], + ['-1,000.45', [-1000.454, 4, 2]], + ['-1,000.45', ['-1000.454', 4, 2]], ['30 µ', [0.00003, 3, 2]], ['3 m', [0.003, 3, 3]], ['-3,000 µ', [-0.003, 6, 0]], @@ -619,7 +619,7 @@ class UtilTest extends AbstractTestCase ['0', [0.0]], ['0', ['0']], ['0', ['0.0']], - [' <0.001', [0.000001, 0, 3]], + ['<0.001', [0.000001, 0, 3]], ['5 m', [0.005]], ['5 µ', [0.000005]], ['5 n', [0.000000005]], @@ -628,6 +628,9 @@ class UtilTest extends AbstractTestCase ['5 a', [0.000000000000000005]], ['5 z', [0.000000000000000000005]], ['5 y', [0.000000000000000000000005]], + ['5 r', [0.000000000000000000000000005]], + ['5 q', [0.000000000000000000000000000005]], + ['<1 q', [0.000000000000000000000000000000005]], ['5 k', [5000]], ['5 M', [5000000]], ['5 G', [5000000000]], @@ -636,8 +639,11 @@ class UtilTest extends AbstractTestCase ['5 E', [5000000000000000000]], ['5 Z', [5000000000000000000000]], ['5 Y', [5000000000000000000000000]], + ['5 R', [5000000000000000000000000000]], + ['5 Q', [5000000000000000000000000000000]], + ['5,000 Q', [5000000000000000000000000000000000]], ['100 m', [0.1, 3, 0]], - [' <1 ', [0.1, 3, 0, true]], + ['<1', [0.1, 3, 0, true]], ['1.000 k', [1000, 3, 3, false, false]], ]; }