array_first() and array_last(): PHP 8.5 Finally Gives Us the Obvious Functions
PHP 8.5 adds array_first() and array_last() to read the ends of an array without touching the internal pointer. Here is how they work and why they matter.
Every PHP developer has written some version of this line at least once: $first = reset($array); or $last = end($array);, then paused for half a second wondering whether that call just quietly moved the array’s internal pointer under their feet. It did. PHP 8.5, released on November 20, 2025, closes that small but persistent gap with two functions that should have existed years ago: array_first() and array_last().
They do exactly what the names say. Give them an array, get back the first or last value. No pointer manipulation, no keys, no surprises.
The signatures
Both functions take a single array and return a value of any type:
function array_first(array $array): mixed {}
function array_last(array $array): mixed {}
Here they are in practice, drawn straight from the behavior documented on PHP.Watch:
array_first([1, 2, 3]); // 1
array_first(['a' => 2, 'b' => 1]); // 2
array_first([null, 2, 3]); // null
array_first([]); // null
array_last([1, 2, 3]); // 3
array_last(['a' => 2, 'b' => 1]); // 1
array_last([2, 3, null]); // null
array_last([]); // null
The important part is what these functions do not do. They read the value at the first or last key without moving the array’s internal cursor. That is the behavior you almost always wanted from reset() and end(), and the reason those two have caused so many subtle bugs over the years.
Why reset() and end() were a trap
reset() and end() were never designed as “get me the first value” helpers. They exist to manipulate an array’s internal pointer, and returning the value at the new pointer position is a side effect. That side effect made them convenient enough that everyone reached for them, but the pointer movement is real and it bites.
Consider a function that receives an array and peeks at its first element:
function describe(array $items): string
{
$first = reset($items); // moves $items pointer to the start
// ... more logic that uses each() or current() ...
return "starts with {$first}";
}
Because arrays are passed by value in PHP, the pointer damage here stays local, so this particular example survives. The danger shows up when you operate on an array you hold by reference, inside a loop that relies on current() or next(), or when you pass the same array through several helpers that each call reset(). The pointer is shared state, and shared state in a language that otherwise copies arrays freely is a source of confusion. array_first() and array_last() sidestep the whole category of problem by never touching the pointer at all.
They complete a set started in 7.3
If these functions feel overdue, that is because PHP already gave us half the pair back in 7.3 with array_key_first() and array_key_last(). Those return the keys at the ends of an array. What was missing was the value equivalent, which left developers writing this every time:
// The old dance to safely get the first value
$first = $array[array_key_first($array)] ?? null;
That line is correct and pointer-safe, but it is noise. array_first($array) says the same thing and reads like a sentence. In fact the internal implementation is essentially that same expression, wrapped up for you. The polyfill spelled out by PHP.Watch makes the relationship obvious:
function array_first(array $array): mixed {
return $array === [] ? null : $array[array_key_first($array)];
}
function array_last(array $array): mixed {
return $array === [] ? null : $array[array_key_last($array)];
}
The one edge case to keep in mind
Because both functions return null for an empty array, you cannot distinguish “the array was empty” from “the first value happens to be null” by the return value alone. array_first([null, 2, 3]) and array_first([]) both hand you null. If that distinction matters in your code, check $array === [] first, or reach for array_key_first() and test for a valid key. For the overwhelming majority of cases, where you just want a value or a sensible empty fallback, the null return is exactly right.
Getting them before PHP 8.5
If you are not on 8.5 yet, you are not locked out. The functions are trivial to polyfill using the 7.3 key helpers shown above, or you can pull in a maintained package that covers PHP 7.3 through 8.4:
composer require polyfills/array-first-array-last
One backward-compatibility note worth flagging for older codebases: if your application already declares its own global array_first() or array_last() function, upgrading to PHP 8.5 will trigger a fatal redeclaration error. The fix is straightforward. Remove your custom version, rename it, or move it into a namespace. For everyone else, the upgrade is invisible.
A note for Laravel and framework users
If you live in Laravel, you have had Arr::first(), Arr::last(), and the first() and last() collection methods for a long time, and those do more, including accepting a callback to find the first matching element. The native functions are not trying to replace those. What they change is the plain-PHP layer underneath: library code, packages that avoid framework dependencies, and the small utility functions where pulling in a collection would be overkill. Having a pointer-safe, dependency-free way to grab the ends of an array in the standard library is a genuine quality-of-life improvement for that kind of code.
The bigger picture
This RFC, authored by Niels Dossche, passed unanimously with 35 votes in favor and none against, with voting running from April 22 to May 6, 2025. A clean sweep like that tells you something: nobody had a reasonable argument against it, and most people had quietly wanted it for years. That is the nicest kind of language change. It adds no new concepts, it makes no code slower, and it removes a small papercut that every PHP developer has felt. You will not rearchitect anything around array_first(), but you will reach for it constantly, and your array-handling code will read a little more honestly for it.