Number::clamp

Constrains a number to a minimum and maximum, returning the nearest bound when it falls outside.

Signature
Number::clamp(int|float $number, int|float $min, int|float $max): int|float
  • Added in Laravel 10.40.0

Parameters

ParameterTypeDescription
$$numberint|floatThe value to constrain.
$$minint|floatLower bound, returned when the number is below it.
$$maxint|floatUpper bound, returned when the number is above it.

Return value

int|floatThe number itself when inside the range, otherwise whichever bound it exceeded.

Changelog

  • PHP 10.40.0Added to the Number class.

Number::clamp() is min(max($number, $min), $max) with a readable name. It replaces the three-line if ladder you would otherwise write around a per-page parameter, a progress percentage or a retry count.

No intl, no exceptions

Along with Number::trim and Number::pairs, this is one of the three methods on the class that never touches NumberFormatter. It works on any PHP build and never throws — which also means it will not tell you when the arguments are nonsense.

Inverted bounds fail silently

Pass min: 100, max: 10 and every input returns 10, because max() lifts the value to 100 and min() then pushes it down to 10. There is no validation, so a swapped pair produces a constant instead of an error. If the bounds come from user input or configuration, sort them before calling.

Types pass through

The return type follows the arguments: clamp an int between ints and you get an int back; introduce a float anywhere and the result may be a float. Do not assume you can use the result as an array key without casting.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Keeping a per_page query parameter inside a supported range before it reaches a paginator
  • Capping a computed progress value at 0 and 100 for a bar's width
  • Bounding an exponential backoff delay so a retry never sleeps for an hour

Frequently asked questions

Does Number::clamp need the intl extension?

No. It is a plain min/max call with no NumberFormatter involved, so it works on any PHP build. Only clamp(), trim() and pairs() are free of that requirement.

What happens if min is greater than max?

Every input returns max, silently. The implementation is min(max($number, $min), $max), so an inverted pair collapses to a constant. Sort the bounds yourself if they come from configuration or user input.

Does Number::clamp return an int or a float?

Whatever min(), max() produce from your arguments — clamping ints between ints gives an int, and a float in any position can give a float back. Cast explicitly if the result is used as an array key or in a strict-typed signature.

More examples

Bounding a request parameter

A request for per_page=100000 is quietly served 100 rows instead of attempting to page the whole table, and per_page=0 becomes 5 rather than triggering a division by zero inside the paginator. The cast to int happens first, because clamp() does no type coercion of its own.

Example · php
<?php

use Illuminate\Http\Request;
use Illuminate\Support\Number;

class PostController
{
    public function index(Request $request)
    {
        $perPage = Number::clamp((int) $request->integer('per_page', 25), min: 5, max: 100);

        return Post::query()->paginate($perPage);
    }
}

Capped exponential backoff

The delay doubles — 1, 2, 4, 8 — and then flattens at 300 seconds from attempt 9 onward instead of growing to 17 minutes. Clamping the ceiling is what turns a textbook backoff formula into one that is safe to ship.

Example · php
<?php

use Illuminate\Support\Number;

function backoffSeconds(int $attempt): int
{
    return (int) Number::clamp(2 ** $attempt, min: 1, max: 300);
}

foreach (range(0, 10) as $attempt) {
    printf("attempt %-3d wait %ds\n", $attempt, backoffSeconds($attempt));
}

Progress that cannot leave the bar

Prints 0%, 70% and 100%. The last case is the useful one: a job that reports more completed items than it planned would otherwise render a bar wider than its container.

Example · php
<?php

use Illuminate\Support\Number;

function progress(int $done, int $total): string
{
    $raw = $total > 0 ? $done / $total * 100 : 0;

    return Number::percentage(Number::clamp($raw, min: 0, max: 100));
}

echo progress(0, 0), PHP_EOL;
echo progress(7, 10), PHP_EOL;
echo progress(12, 10), PHP_EOL;

Discussion

  • Be the first to comment on this lesson.