【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调用在这个程度上产生显著差异,究竟是出于什么样的用例呢?

广告
将在 10 秒后关闭
bannerAds