PHP 8.6:新增 clamp 函数
PHP 8.6 引入了一个新的 clamp 函数,用于检查给定值是否在给定的范围内。如果值在范围内,则返回原始值;如果不在范围内,则 clamp 返回最接近的上限值。
换句话说,clamp 函数可以将给定值“限制”到下限或上限。
PHP 中的新 clamp 函数与其他编程语言(例如 C++ (std::clamp)、C# (Math.Clamp)、Go (cmp.Clamp)、Java (Math.clamp) 和 Python (np.clip))的语义相同。
clamp 函数
function clamp(?mixed $value, ?mixed $min, ?mixed $max): ?mixed参数 $value 的值被限制在 $min 和 $max 的范围内(包含 $min 和 $max)。
- 该函数声明在全局命名空间中。
- 如果
$min的值大于$max,则会抛出ValueError异常。
$min 和 $max 都不能为 NaN,否则会抛出 ValueError 异常。
- 比较不同类型的值时,会使用比较规则。请注意,这些规则可能并不直观,尤其是在比较数组、对象和布尔值时。
使用示例
Integer clamping:
clamp(5, 0, 100); // 5
clamp(0, 0, 100); // 0
clamp(-5, 0, 100); // 0
clamp(100, 0, 100); // 100
clamp(105, 0, 100); // 100
clamp(105, 100, 100); // 100Float clamping:
clamp(3.01, 1.6, 4.2); // 3.01
clamp(10.0, 1.6, 4.2); // 4.2
clamp(0, M_1_PI, M_2_PI); // 0.31830988618379Integer j及 float clamping
clamp(5, 10, 12.5); // 10
clamp(5, 10.0, 12); // 10.0
clamp(3.14, 10, 20); // 10
clamp(3.14, 0, 20); // 3.14类型不兼容比较
比较除 int 和 float 类型之外的值时,首先将值与上限 ($max) 进行比较,然后再与下限 ($min) 进行比较。
比较不兼容类型
当边界值和值参数的类型不同时,将使用标准类型强制转换规则进行比较。这些规则带有历史遗留问题,且不够直观。建议在边界值和/或值类型不兼容时手动比较值,而不是使用 clamp 函数。
strict_types 对此比较行为没有影响。
clamp 函数不会引入任何新的比较语义。
在内部,首先检查上限 ($value > $max)。如果结果为真,则返回 $max 值。其次,检查 $value < $min,如果结果为真,则返回 $min。最后,如果两个比较结果均为假,则返回 $value。
此行为解释了下面所示的不同类型之间的钳制行为:
String 值
如果三个参数均为非数字字符串,则按字典顺序进行求值:
clamp('P', 'A', 'Z'); // "P"
clamp('P', 'X', 'Z'); // "X"
clamp('P', 'A', 'C'); // "C"
clamp('AAA', 'AA', 'Z'); // "AAA"Boolean 值
clamp(5, false, true); // 5
clamp(true, false, true); // true
clamp(true, false, false); // false
clamp(false, true, true); // true
clamp(false, true, 5); // true数组
clamp(5, [], []); // []
clamp(5, 0, []); // 5
clamp(5, false, []); // 5
clamp([3], [1], [5]); // [3]
clamp([1], [3], [5]); // [3]
clamp([1, 4], [3], [1, 5]); // [1, 4]对象
对象之间也使用相同的 > 和 < 运算符进行比较。如果对象支持重载比较,则会执行相应的比较操作。
例如,DateTime/DateTimeImmutable 类和 BCMath\Number 类支持对象比较。它们与 clamp 函数兼容:
clamp(new DateTimeImmutable('2026-01-08'), new DateTimeImmutable('2026-01-01'), new DateTimeImmutable('2026-12-31'));
// DateTimeImmutable('2026-01-08')
clamp(new BCMath\Number('36'), new BCMath\Number('16'), new BCMath\Number('42'));
// BCMath\Number('36')用户端 Polyfill
新的 clamp 函数可以轻松地使用用户端 PHP 代码进行 Polyfill:
/**
* Return the given value if in range, otherwise return the nearest bound.
*/
function clamp(mixed $value, mixed $min, mixed $max): mixed {
if (\is_float($min) && \is_nan($min)) {
throw new \ValueError('clamp(): Argument #2 ($min) must not be NAN');
}
if (\is_float($max) && \is_nan($max)) {
throw new \ValueError('clamp(): Argument #3 ($max) must not be NAN');
}
if ($max < $min) {
throw new \ValueError('clamp(): Argument #2 ($min) must be smaller than or equal to argument #3 ($max)');
}
if ($value > $max) {
return $max;
}
if ($value < $min) {
return $min;
}
return $value;
}向后兼容性影响
新的 clamp 函数声明在全局命名空间中。除非 PHP 应用自行声明了 clamp 函数,否则此更改不会破坏向后兼容性。
可以在旧版 PHP 函数中使用 polyfill 来支持 clamp 函数。