PHP 8.2 特性 - 新增 ini_parse_quantity 函数
PHP INI 指令接受可包含后缀的数据大小,用以指定单位乘数,比如 5M或者 1G。这些后缀在 PHP INI 文件中广泛使用,不过并不是国际标准后缀。
ini_parse_quantity
是在 PHP 8.2 中新加入 PHP 的函数。该函数解析由 PHP INI 值可以识别的任何数据大小(比如 56K、256M、1G) 并以 byte 返回数据大小(size)。该函数在解析现有的或提供的 INI 值时会非常有用。
ini_parse_quantity
函数不能识别 IEC 后缀,比如 MB、MiB 或 GB,并且不适于将标准数据大小值转成 byte。
比如,PHP INI 和 ini_parse_quantity
函数中的 1K 被当成是 1KB,也就是 1024 byte。ini_parse_quantity
返回解析后的 byte 值。
ini_parse_quantity 函数概要
function ini_parse_quantity(string $shorthand): int {
}
ini_parse_quantity
函数通过检测字符后缀尝试解析给定的 $shorthand
值,返回值会乘以指定单位对应的数值。
下表是后缀对应的名称和乘数值:
Suffix | Name | Multiplier |
---|---|---|
k / K | Kibibytes | 1024 |
m / M | Megabytes | 1048576 |
g / G | Gigabytes | 1073741824 |
请注意该函数在碰到不能识别的后缀时(e.g 53Q),将会发送警告;在碰到解析的 byte 值溢出(9999999999G)或如果解析器忽视未识别的字符时(12RG),没有前导数字(R2D2)。并且不会抛出任何异常,调用者可能需要去检查警告信息,确保值可以正确解析。
另外,该函数不能识别小数值(1.5G)。
ini_parse_quantity
函数 (及 PHP 内部解析的 INI value ) 用于尝试绕过错误格式的字符串,使之不会抛出异常。如果该函数最终不能解析某个值,则会返回 0。
函数警告信息
ini_parse_quantity
函数如果碰到不符合格式的值时,会发送多种不同类型的警告。
- 不带前导数字的值会返回 0
不带前导数字的值,比如 ABC、T5、S05e06,将会无效。会产生警告并返回 0 :
- 后缀不可识别的值 返回最先发现的整数值
函数不能识别的单位会被忽略,并且返回传入值中包含的绝对整型值。- 123R2D2 解析为 "123"
- 1234T 解析为 "123"
- -1234T 解析为 "-123"
- 值的中间包含不可识别的字符时 返回数量值并发出警告
如果解析的值包含移除的字符,会发出警告,不过函数还是返回解析后的量化值。- 123FG 被解析成 "123G" 对应 132070244352
- 123$M 被解析成 "123M" 对应 44040192
- -123MM 被解析成 "-123M" 对应 -128974848
- 溢出的值 返回溢出后的值
如果计算的值超出 CPU 所能处理的最大、最小整型值,会发出警报,并且函数会返回溢出值。- 9999999999G 被计算为 -7709325834783293440
- -9999999999G 被计算为 7709325834783293440
用户空间的 PHP 实现
下例是 PHP 8.2 的 ini_parse_quantity
函数在 PHP 用户空间中的实现,可以在 PHP 7.0 及以上版本中运行。与 PHP 8.2 的 ini_parse_quantity
发出同样的警告。
function ini_parse_quantity(string $shorthand): int {
$original_shorthand = $shorthand;
$multiplier = 1;
$sign = '';
$return_value = 0;
$shorthand = trim($shorthand);
// Return 0 for empty strings.
if ($shorthand === '') {
return 0;
}
// Accept + and - as the sign.
if ($shorthand[0] === '-' || $shorthand[0] === '+') {
if ($shorthand[0] === '-') {
$multiplier = -1;
$sign = '-';
}
$shorthand = substr($shorthand, 1);
}
// If there is no suffix, return the integer value with the sign.
if (preg_match('/^\d+$/', $shorthand, $matches)) {
return $multiplier * $matches[0];
}
// Return 0 with a warning if there are no leading digits
if (preg_match('/^\d/', $shorthand) === 0) {
trigger_error(sprintf('Invalid quantity "%s": no valid leading digits, interpreting as "0" for backwards compatibility', $original_shorthand), E_USER_WARNING);
return $return_value;
}
// Removing whitespace characters.
$shorthand = preg_replace('/\s/', '', $shorthand);
$suffix = strtoupper(substr($shorthand, -1));
switch ($suffix) {
case 'K':
$multiplier *= 1024;
break;
case 'M':
$multiplier *= 1024 * 1024;
break;
case 'G':
$multiplier *= 1024 * 1024 * 1024;
break;
default:
preg_match('/\d+/', $shorthand, $matches);
trigger_error(sprintf('Invalid quantity "%s": unknown multiplier "%s", interpreting as "%d" for backwards compatibility', $original_shorthand, $suffix, $sign . $matches[0]), E_USER_WARNING );
return $matches[0] * $multiplier;
}
$stripped_shorthand = preg_replace('/^(\d+)(\D.*)([kKmMgG])$/', '$1$3', $shorthand, -1, $count);
if ($count > 0) {
trigger_error(sprintf('Invalid quantity "%s", interpreting as "%s" for backwards compatibility', $original_shorthand, $sign . $stripped_shorthand), E_USER_WARNING);
}
preg_match('/\d+/', $shorthand, $matches);
$multiplied = $matches[0] * $multiplier;
if (is_float($multiplied)) {
trigger_error(sprintf('Invalid quantity "%s": value is out of range, using overflow result for backwards compatibility', $original_shorthand), E_USER_WARNING);
}
return (int) ($matches[0] * $multiplier);
}
向后兼容性影响
ini_parse_quantity
是 PHP 8.2 中新增的函数。该函数与映射到 PHP 引擎的一些内部代码一起添加,会导致解析 INI 文件时发出警告。
不过,如果应用或者库想使其在旧版本中使用,该函数可以在用户空间代码中实现。
Invalid quantity "S06e08": no valid leading digits, interpreting as "0" for backwards compatibility