Arrays7 min readExamples run on PHP 8.5.10

key()

Learn how PHP key() returns the key at an array's internal pointer, when it gives null, and how to avoid pointer-related mistakes.

Signature

key(array|object $array): int|string|null

Purpose

Every PHP array carries an internal pointer that marks one element as the "current" one. key() reports the key of that element. It only reads the pointer. It never moves it, so calling it ten times in a row gives the same answer ten times.

The pointer is controlled by a family of functions: current() returns the value, next() and prev() step the pointer, reset() sends it to the first element, and end() sends it to the last. key() is the companion that tells you where you are, in terms of keys rather than values.

Signature

Parameters and defaults

  • $array is the array whose pointer is inspected. There are no other parameters and no default values.
  • The signature also lists object, but calling key() on an object has been deprecated since PHP 8.1. If you need the same behaviour for an object, convert it first with get_mangled_object_vars(), or use an iterator class such as ArrayIterator that has its own key() method. For ordinary work, pass arrays only.

Return value and failure cases

  • It returns an int or string: the key of the element the pointer currently references.
  • It returns null if the pointer has moved beyond the last element, or if the array is empty.
  • Because an array key can never be null, a null result is unambiguous: it always means "no current element".

A fresh array has its pointer on the first element, so key() on a new array gives its first key without any setup.

Example 1: walking the pointer

This example shows the key at the start, after one step, and after stepping past the end.

Example
<?php
$stack = ['a' => 10, 'b' => 20, 'c' => 30];
echo json_encode(key($stack)), "\n";
next($stack);
echo json_encode(key($stack)), "\n";
next($stack);
next($stack);
echo json_encode(key($stack)), "\n";
Output
"a"
"b"
null

The first call reports "a", the second "b", and after moving past "c" the result is null.

Example 2: key() does not advance

Integer keys continue from the highest previous integer key, so [5 => 'x', 'y', 'z'] has keys 5, 6 and 7. Repeated calls do not change the pointer; only next() does.

Example
<?php
$list = [5 => 'x', 'y', 'z'];
echo key($list), "\n";
echo key($list), "\n";
echo current($list), "\n";
next($list);
echo key($list), ':', current($list), "\n";
Output
5
5
x
6:y

Example 3: collecting matching keys safely

A common use is scanning an array and recording the keys of matching values. The loop condition tests key() against null instead of testing the value, so falsy values such as 0 do not end the loop early.

Example
<?php
$flags = ['a' => 'apple', 'b' => 0, 'c' => 'apple', 'd' => 'pear'];
$found = [];
while (($k = key($flags)) !== null) {
    if (current($flags) === 'apple') {
        $found[] = $k;
    }
    next($flags);
}
echo json_encode($found), "\n";
Output
["a","c"]

The result is ["a","c"]. Had the loop used while ($value = current($flags)), it would have stopped at the 0 under key b.

Edge cases

  • Empty arrays: key([]) returns null.
  • Pointer past the end: once next() has moved beyond the last element, key() stays null until you call reset() or end().
  • Numeric string keys: a key such as "7" is stored as the integer 7, so key() returns an int for it.
  • foreach: a foreach loop does not use or move the internal pointer in modern PHP, so it will not change what key() returns, and key() will not tell you the current foreach position.
  • Copies: the pointer is part of the array value. Work with the variable you actually moved, not a different copy of it.

Common mistakes

  1. Expecting key() to advance. It never does. Pair it with next() explicitly.
  2. Looping on the value. while ($v = current($a)) stops at the first falsy value. Test key($a) !== null instead.
  3. Using a loose null check. Keys such as 0 and "" are valid, and 0 is falsy. Always compare with !== null.
  4. Forgetting reset(). If earlier code moved the pointer, key() will not give the first key. Call reset() first when you need a known starting point.
  5. Passing objects. This is deprecated since PHP 8.1; use arrays or iterator classes.
  6. Reaching for key() when you only want the first key. array_key_first() is clearer and does not depend on pointer state.
  • current() returns the value at the pointer.
  • next() advances the pointer and prev() moves it back.
  • reset() and end() jump to the first and last elements.
  • array_key_first() and array_key_last() fetch boundary keys without touching the pointer.
  • foreach iterates keys and values without manual pointer handling.

Recap

key() reads the key at an array's internal pointer and returns int|string|null. It does not move the pointer, and it returns null for an empty array or when the pointer is past the end. Loop with key($array) !== null, step with next(), and avoid objects, which are deprecated since PHP 8.1.

Tested examples

Walking the pointer with next()
<?php
$stack = ['a' => 10, 'b' => 20, 'c' => 30];
echo json_encode(key($stack)), "\n";
next($stack);
echo json_encode(key($stack)), "\n";
next($stack);
next($stack);
echo json_encode(key($stack)), "\n";
Output
"a"
"b"
null
key() does not advance the pointer
<?php
$list = [5 => 'x', 'y', 'z'];
echo key($list), "\n";
echo key($list), "\n";
echo current($list), "\n";
next($list);
echo key($list), ':', current($list), "\n";
Output
5
5
x
6:y
Collecting matching keys safely
<?php
$flags = ['a' => 'apple', 'b' => 0, 'c' => 'apple', 'd' => 'pear'];
$found = [];
while (($k = key($flags)) !== null) {
    if (current($flags) === 'apple') {
        $found[] = $k;
    }
    next($flags);
}
echo json_encode($found), "\n";
Output
["a","c"]