Skip to content

Commit a137881

Browse files
committed
- Use a common function for normal and frameless implementations
- Add tests for null and not-comparable cases - Fix object support for frameless clamp function - Improve NAN handling
1 parent 27f144a commit a137881

File tree

3 files changed

+89
-38
lines changed

3 files changed

+89
-38
lines changed

ext/standard/basic_functions_arginfo.h

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/standard/math.c

Lines changed: 31 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -389,31 +389,47 @@ PHP_FUNCTION(round)
389389
}
390390
/* }}} */
391391

392-
/* {{{ Return the given value if in range of min and max */
393-
PHP_FUNCTION(clamp)
392+
/* Return the given value if in range of min and max */
393+
static void php_math_clamp(zval *return_value, zval *value, zval *min, zval *max)
394394
{
395-
zval *zvalue, *zmin, *zmax;
395+
if (Z_TYPE_P(min) == IS_DOUBLE && UNEXPECTED(zend_isnan(Z_DVAL_P(min)))) {
396+
zend_argument_value_error(2, "cannot be NAN");
397+
RETURN_THROWS();
398+
}
396399

397-
ZEND_PARSE_PARAMETERS_START(3, 3)
398-
Z_PARAM_ZVAL(zvalue)
399-
Z_PARAM_ZVAL(zmin)
400-
Z_PARAM_ZVAL(zmax)
401-
ZEND_PARSE_PARAMETERS_END();
400+
if (Z_TYPE_P(max) == IS_DOUBLE && UNEXPECTED(zend_isnan(Z_DVAL_P(max)))) {
401+
zend_argument_value_error(3, "cannot be NAN");
402+
RETURN_THROWS();
403+
}
402404

403-
if (zend_compare(zmin, zmax) > 0) {
405+
if (zend_compare(max, min) == -1) {
404406
zend_argument_value_error(2, "must be smaller than or equal to argument #3 ($max)");
405407
RETURN_THROWS();
406408
}
407409

408-
if (zend_compare(zmax, zvalue) == -1) {
409-
RETURN_COPY(zmax);
410+
if (zend_compare(max, value) == -1) {
411+
RETURN_COPY(max);
410412
}
411413

412-
if (zend_compare(zvalue, zmin) == -1) {
413-
RETURN_COPY(zmin);
414+
if (zend_compare(value, min) == -1) {
415+
RETURN_COPY(min);
414416
}
415417

416-
RETURN_COPY(zvalue);
418+
RETURN_COPY(value);
419+
}
420+
421+
/* {{{ Return the given value if in range of min and max */
422+
PHP_FUNCTION(clamp)
423+
{
424+
zval *zvalue, *zmin, *zmax;
425+
426+
ZEND_PARSE_PARAMETERS_START(3, 3)
427+
Z_PARAM_ZVAL(zvalue)
428+
Z_PARAM_ZVAL(zmin)
429+
Z_PARAM_ZVAL(zmax)
430+
ZEND_PARSE_PARAMETERS_END();
431+
432+
php_math_clamp(return_value, zvalue, zmin, zmax);
417433
}
418434
/* }}} */
419435

@@ -425,20 +441,7 @@ ZEND_FRAMELESS_FUNCTION(clamp, 3)
425441
Z_FLF_PARAM_ZVAL(2, zmin);
426442
Z_FLF_PARAM_ZVAL(3, zmax);
427443

428-
if (zend_compare(zmin, zmax) > 0) {
429-
zend_argument_value_error(2, "must be smaller than or equal to argument #3 ($max)");
430-
RETURN_THROWS();
431-
}
432-
433-
if (zend_compare(zmax, zvalue) == -1) {
434-
RETURN_COPY_VALUE(zmax);
435-
}
436-
437-
if (zend_compare(zvalue, zmin) == -1) {
438-
RETURN_COPY_VALUE(zmin);
439-
}
440-
441-
RETURN_COPY_VALUE(zvalue);
444+
php_math_clamp(return_value, zvalue, zmin, zmax);
442445
}
443446
/* }}} */
444447

ext/standard/tests/math/clamp.phpt

Lines changed: 57 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,55 @@ var_dump(clamp(2.5, 1.3, 3.4));
1515
var_dump(clamp(0, 1.3, 3.4));
1616
var_dump(clamp(M_PI, -INF, INF));
1717
var_dump(clamp(NAN, 4, 6));
18-
var_dump(clamp(4, NAN, 6));
19-
var_dump(clamp(8, NAN, 6));
20-
var_dump(clamp(7, 6, NAN));
21-
var_dump(clamp(4, 6, NAN));
2218
var_dump(clamp("a", "c", "g"));
2319
var_dump(clamp("d", "c", "g"));
2420
echo clamp('2025-08-01', '2025-08-15', '2025-09-15'), "\n";
2521
echo clamp('2025-08-20', '2025-08-15', '2025-09-15'), "\n";
2622
echo clamp(new \DateTimeImmutable('2025-08-01'), new \DateTimeImmutable('2025-08-15'), new \DateTimeImmutable('2025-09-15'))->format('Y-m-d'), "\n";
2723
echo clamp(new \DateTimeImmutable('2025-08-20'), new \DateTimeImmutable('2025-08-15'), new \DateTimeImmutable('2025-09-15'))->format('Y-m-d'), "\n";
24+
var_dump(clamp(null, -1, 1));
25+
var_dump(clamp(null, 1, 3));
26+
var_dump(clamp(null, -3, -1));
27+
var_dump(clamp(-9999, null, 10));
28+
var_dump(clamp(12, null, 10));
29+
30+
$a = new \InvalidArgumentException('a');
31+
$b = new \RuntimeException('b');
32+
$c = new \LogicException('c');
33+
echo clamp($a, $b, $c)::class, "\n";
34+
echo clamp($b, $a, $c)::class, "\n";
35+
echo clamp($c, $a, $b)::class, "\n";
36+
37+
try {
38+
var_dump(clamp(4, NAN, 6));
39+
} catch (ValueError $error) {
40+
echo $error->getMessage(), "\n";
41+
}
42+
43+
try {
44+
var_dump(clamp(7, 6, NAN));
45+
} catch (ValueError $error) {
46+
echo $error->getMessage(), "\n";
47+
}
48+
49+
try {
50+
var_dump(clamp(1, 3, 2));
51+
} catch (ValueError $error) {
52+
echo $error->getMessage(), "\n";
53+
}
54+
55+
56+
try {
57+
var_dump(clamp(-9999, 5, null));
58+
} catch (ValueError $error) {
59+
echo $error->getMessage(), "\n";
60+
}
61+
62+
try {
63+
var_dump(clamp(12, -5, null));
64+
} catch (ValueError $error) {
65+
echo $error->getMessage(), "\n";
66+
}
2867

2968
?>
3069
--EXPECT--
@@ -36,14 +75,23 @@ float(2.5)
3675
float(2.5)
3776
float(1.3)
3877
float(3.141592653589793)
39-
double(NAN)
40-
int(4)
41-
int(6)
42-
int(7)
43-
int(6)
78+
float(NAN)
4479
string(1) "c"
4580
string(1) "d"
4681
2025-08-15
4782
2025-08-20
4883
2025-08-15
4984
2025-08-20
85+
int(-1)
86+
int(1)
87+
int(-3)
88+
int(-9999)
89+
int(10)
90+
InvalidArgumentException
91+
RuntimeException
92+
LogicException
93+
clamp(): Argument #2 ($min) cannot be NAN
94+
clamp(): Argument #3 ($max) cannot be NAN
95+
clamp(): Argument #2 ($min) must be smaller than or equal to argument #3 ($max)
96+
clamp(): Argument #2 ($min) must be smaller than or equal to argument #3 ($max)
97+
clamp(): Argument #2 ($min) must be smaller than or equal to argument #3 ($max)

0 commit comments

Comments
 (0)