PHP 8.6: New clamp function

Version8.6
TypeNew Feature

PHP 8.6 introduces a new clamp function that checks if a given value is within a given bound. If the value is within that bound, the original value is returned. If it is not within the bounds, clamp returns the closest bound.

In other words, the clamp function can "clamp" a given value to lower and higher bounds.

The new clamp function in PHP follows the same semantics as other programming languages such as C++ (std::clamp), C# (Math.Clamp), Go (cmp.Clamp), Java (Math.clamp), and Python (np.clip).

clamp function

function clamp(?mixed $value, ?mixed $min, ?mixed $max): ?mixed

The parameter $value is clamped inclusively within the range $min and $max.

  • The function is declared in the global namespace.
  • If the $min value is larger than $max, a ValueError exception is thrown.
  • Neither $min nor $max can be NAN, otherwise, a ValueError is thrown.
  • When comparing values of different types, comparison rules are used. Note that they may not be as intuitive, especially when comparing arrays, objects, and boolean values.

Usage Examples

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); // 100

Float 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.31830988618379

Integer and 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

Incompatible Type Comparisons

When comparing values of types other than int and float, the value is first compared to the upper bound ($max), and then against the lower bound ($min).

Comparing incompatible types

When the boundary values and the value parameters are of different types, the values are compared using the standard type coercion rules. They carry historical baggage, and are not intuitive. It is recommended to compare the values manually instead of using the clamp function when the boundaries and/or values are type-incompatible.

strict_types has no impact on this comparison behavior.

The clamp function does not introduce any new comparison semantics.

Internally, the upper bound is checked first ($value > $max). If this evaluates to true, the $max value is returned. Second, $value < $min, which returns $min if it evaluates to true. Finally, if both comparisons evaluated to false, the $value is returned.


This behavior explains the clamping behavior shown below across different types:

String values

If all three parameters are non-numeric strings, they are evaluated lexicographically:

clamp('P', 'A', 'Z'); // "P"
clamp('P', 'X', 'Z'); // "X"
clamp('P', 'A', 'C'); // "C"
clamp('AAA', 'AA', 'Z'); // "AAA"

Boolean values

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

Arrays

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]

Objects

Objects are also compared with the same > and < operators. If the objects support overloaded comparisons, they are evaluated.

For example, the DateTime/DateTimeImmutable classes and BCMath\Number classes support comparing objects. They are compatible with the clamp function:

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')

Userland Polyfill

The new clamp function can be trivially polyfilled with user-land PHP:

/**
 * 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;
}

Backward Compatibility Impact

The new clamp function is declared in the global namespace. Unless the PHP application declares a clamp function on its own, this change has no BC breakages.

It is possible to polyfill the clamp function in older PHP functions.


clamp RFC Discussion Implementation