Signature
range(string|int|float $start, string|int|float $end, int|float $step = 1): arrayPurpose
range() builds an array from a starting value to an ending value. You give it the two boundaries and, optionally, the distance between neighbouring elements. It is a compact way to produce page numbers, index lists, countdowns, alphabet slices or evenly spaced floats without writing a loop.
Signature
Parameters and defaults
$startis the first value of the sequence.$endis the last possible value. The sequence stops at$endor at the last element before it, depending on$step.$stepis the distance between values. It defaults to1. A float step with no fractional part is treated as an integer.
The direction comes from the boundaries, not from the sign of the step. If $start is less than or equal to $end, the sequence increases. Otherwise it decreases. A positive step is therefore fine for a decreasing range, and range(5, 1, 2) counts down.
Return value
The function always returns a list-style array. The element type depends on the input:
- If both boundaries are strings and the step is an integer, the result is a sequence of bytes, generally ASCII characters.
- If at least one of
$start,$endor$stepis a float, the result is a sequence of floats. - Otherwise the result is a sequence of integers.
Failure cases
PHP 8.4 throws a ValueError when:
$stepis0.$start,$endor$stepis not finite, such asINForNAN.$stepis negative but the range is increasing ($start <= $end).
A TypeError is thrown if $start or $end is an array, object or resource. An E_WARNING is emitted if a boundary is an empty string (treated as 0), a non-numeric string longer than one byte, or a string that must be cast to an integer because the other boundary is a number.
Example 1: integers and steps
The default step is 1. A larger step skips values, and a decreasing range works with a positive step.
echo json_encode(range(1, 5)), PHP_EOL;
echo json_encode(range(0, 100, 25)), PHP_EOL;
echo json_encode(range(5, 1, 2)), PHP_EOL;[1,2,3,4,5] [0,25,50,75,100] [5,3,1]
The last call produces 5, 3, 1. The value 1 is reached exactly, so it is included.
Example 2: characters and floats
When both boundaries are strings, range() walks through byte values. With a float step you get float values.
echo json_encode(range('a', 'e')), PHP_EOL;
echo json_encode(range('e', 'a', 2)), PHP_EOL;
echo implode(',', range(0, 1, 0.25)), PHP_EOL;["a","b","c","d","e"] ["e","c","a"] 0,0.25,0.5,0.75,1
The character example uses the ASCII order of the bytes. This is why a range such as 'A' to 'z' also includes punctuation characters that sit between uppercase and lowercase letters.
Example 3: handling invalid steps
Because a bad step throws, wrap dynamic input in a small helper if it comes from outside your code.
function tryRange(int|float|string $start, int|float|string $end, int|float $step): string
{
try {
return json_encode(range($start, $end, $step));
} catch (ValueError $e) {
return 'ValueError';
}
}
echo tryRange(1, 3, 0), PHP_EOL;
echo tryRange(1, 3, -1), PHP_EOL;
echo tryRange(3, 1, -1), PHP_EOL;ValueError ValueError [3,2,1]
A zero step and a negative step on an increasing range both fail. A negative step on a decreasing range is valid.
Edge cases
- Equal boundaries: if
$startequals$end, the result contains that single value. - Step larger than the span: the array contains only
$start, because the next value would overshoot$end. - Steps that do not land on the end:
range(0, 10, 4)ends at8, not10. - Float precision: decimal fractions such as
0.1cannot be represented exactly in binary. Round the values or compare with a tolerance before testing them for equality. - Keys: the keys are always
0, 1, 2, …, regardless of the values. - Size: the whole array is built in memory. For a very large span, a
forloop or a generator is a better fit.
Common mistakes
- Using a negative step for an increasing range. In PHP 8.3 and later this throws a
ValueError. Use a positive step, or swap the boundaries. - Passing
0as the step. Validate user-supplied steps before calling the function. - Mixing numbers and strings. A call like
range('a', 5)forces one boundary to be cast and produces a warning. Pass values of the type you intend. - Passing multi-character strings. Non-numeric strings longer than one byte trigger a warning, so
range('aa', 'zz')does not produce two-letter combinations. - Expecting inclusive ends every time. The end is only included when the step lands exactly on it.
- Assuming
range()is lazy. It allocates every element at once.
Related functions
array_fill()creates an array of repeated values for a given index range.shuffle()randomizes the order of an existing array, which is useful after generating a range.foreachiterates over the produced array.array_map()andarray_filter()can transform or trim a generated range.
Recap
range() creates an array from $start to $end using an optional $step. The direction depends on the boundaries, the element type depends on the arguments, and it throws a ValueError for a zero, non-finite or wrongly signed step. Keep the argument types consistent, remember that the end value is not guaranteed to appear, and avoid it for extremely large spans.
Tested examples
echo json_encode(range(1, 5)), PHP_EOL;
echo json_encode(range(0, 100, 25)), PHP_EOL;
echo json_encode(range(5, 1, 2)), PHP_EOL;[1,2,3,4,5] [0,25,50,75,100] [5,3,1]
echo json_encode(range('a', 'e')), PHP_EOL;
echo json_encode(range('e', 'a', 2)), PHP_EOL;
echo implode(',', range(0, 1, 0.25)), PHP_EOL;["a","b","c","d","e"] ["e","c","a"] 0,0.25,0.5,0.75,1
function tryRange(int|float|string $start, int|float|string $end, int|float $step): string
{
try {
return json_encode(range($start, $end, $step));
} catch (ValueError $e) {
return 'ValueError';
}
}
echo tryRange(1, 3, 0), PHP_EOL;
echo tryRange(1, 3, -1), PHP_EOL;
echo tryRange(3, 1, -1), PHP_EOL;ValueError ValueError [3,2,1]