【PHP Next】我希望PHP有一个clamp函数
我与《魔卡少女樱》没有任何关系。
clamp是指将参数的数值限制在一个范围内,CSS已经实现了clamp,因此在CSS中可以很容易地看到它的用法。例如,对于clamp(min=100, max=200),如果传入150,则返回150;如果传入0,则返回100;如果传入300,则返回200。
因此,提出了一项RFC,希望在PHP中添加clamp功能。
以下是相关的RFC,PHP RFC:介绍clamp功能。
PHP RFC:clamp
引言
clamp函数用于检查值是否在给定的范围内。
如果值在范围内,则返回该值;如果值超出范围,则返回边界值。
用户空间的实现有多种,包括使用min和max的实现方式,但由于其计算成本较高,频繁调用会导致性能下降。
由于许多用户空间实现不考虑调用成本,因此希望在语言层面实现它们。
提案
在此RFC中,提议引入一种新的函数clamp。
clamp ( int|float $num, int|float $min, int|float $max ) : int|float
这个函数有三个参数:$num、$min、$max。
它会检查$num是否在$min和$max之间,如果在范围内,则返回$num。
如果不在范围内,则返回$min和$max中较接近的那个。
换句话说,如果$num > $max,则返回$max;如果$num < $min,则返回$min。
如果$max$小于$min$,则抛出ValueError作为无效值。
当其中一个值为NAN时,也会引发ValueError。
作为例子,可以采用以下方式。
clamp(num: 1, min: 0, max: 3); // 1 範囲内
clamp(num: 1, min: 2, max: 5); // 2 小さい
clamp(num: 4, min: 1, max: 3); // 3 大きい
clamp(num: 0, min: 2, max: 1); // clamp(): Argument #2 ($min) cannot be greater than Argument #3 ($max)
不向后兼容的更改 (Bù de
在PHP中没有自身的不兼容更改。
“clamp()”函数名将不能再使用。
PHP版本的提议
PHP8.x
PHP8.x 的版本
未解决的问题
有关NAN的处理方法。
实施
拉取请求
参考文献
类似的实现。
C++
CRAN
CSS
我对此有很多想法。
据说clamp是在IEEE754-2019标准中确定的。虽然看不到,但看来这样的东西也被定义了。
这个函数在PHP中也可以很容易地实现。
function clamp(int|float $num, int|float $min, int|float $max):int|float {
if($max < $min){
throw new \ValueError('clamp(): Argument #2 ($min) cannot be greater than Argument #3 ($max)');
}
if($max < $num){
return $max;
}
if($min > $num){
return $min;
}
return $num;
}
在Pull Request中,用C语言进行的实现几乎相同。
if (zend_compare(zmin, zmax) > 0) {
zend_argument_value_error(2, "must be smaller than or equal to argument #3 ($max)");
RETURN_THROWS();
}
if (zend_compare(zmax, zvalue) == -1) {
RETURN_COPY_VALUE(zmax);
} else if (zend_compare(zvalue, zmin) == -1) {
RETURN_COPY_VALUE(zmin);
} else {
RETURN_COPY_VALUE(zvalue);
}
因此,并不是绝对必要的函数,就像str_contains一样,没有它也能应付,但如果有的话,它是一个方便的辅助函数。
这份RFC于2021年6月提交,并在接下来的一个月左右完成了代码的实施。
然而,之后就完全失去消息,进展停滞不前。
由于作者在其他项目上有各种各样的提交,可能是因为他感到厌倦或觉得麻烦吧。
然而后来,由于一些评论说“我想要这个”,这些评论或许会被逐渐加入到Pull Request中,未来或许会被采纳,也有可能不会。
顺便提一下,以下可能是最简单的实现方法,但同时也是RFC所谓的慢速实现。
function clamp(int|float $num, int|float $min, int|float $max):int|float {
return max($min, min($max, $num));
}
我不知道他是否已经坐在板凳上,但他看起来显然很慢。不过,使用如此大量的clamp调用在这个程度上产生显著差异,究竟是出于什么样的用例呢?