λ!

A blog about all things code

Flattening arrays in PHP

To sum things up; if you want to flatten a two-dimensional array with numeric keys:

array_merge(...$twoDimensionalArray);

If you want to flatten a two-dimensional associative array:

array_merge(...array_values($twoDimensionalArray));

If you want a general solution to flatten an arbitrarily nested array and you don’t care about the keys:

function flatten_array(array $array): array {
    $recursiveArrayIterator = new RecursiveArrayIterator(
        $array,
        RecursiveArrayIterator::CHILD_ARRAYS_ONLY
    );
    $iterator = new RecursiveIteratorIterator($recursiveArrayIterator);

    return iterator_to_array($iterator, false);
}

If you want a general solution to flatten an arbitrarily nested array and you do care about the keys:

function flatten_array_preserve_keys(array $array): array {
    $recursiveArrayIterator = new RecursiveArrayIterator(
        $array,
        RecursiveArrayIterator::CHILD_ARRAYS_ONLY
    );
    $iterator = new RecursiveIteratorIterator($recursiveArrayIterator);

    return iterator_to_array($iterator);
}

As a side note, if you are only interested in all values with a specific key 1:

$array = [
    ['id' => 123, 'name' => 'aaa', 'class' => 'x'],
    ['id' => 124, 'name' => 'bbb', 'class' => 'x'],
    ['id' => 345, 'name' => 'ccc', 'class' => 'y'],
];

array_column($array, 'id');
// [123, 124, 345]

Flattening a two-dimensional array 

array_merge(...$twoDimensionalArray);

array_merge takes a variable list of arrays as arguments and merges them all into one array. By using the splat operator (...), every element of the two-dimensional array gets passed as an argument to array_merge.

This works fine for merging associative arrays as well, but beware that the outer array is only allowed to have numeric keys:

$twoDimensionalArray = [
    'x' => ['first', 'array'],
    'y' => ['second', 'array']
];

$flattenedArray = array_merge(...$twoDimensionalArray);
// Fatal error: Uncaught ArgumentCountError: array_merge() does not accept unknown named parameters

The solution is to use array_values in those cases:

$twoDimensionalArray = [
    'x' => ['first', 'array'],
    'y' => ['second', 'array']
];

$flattenedArray = array_merge(...array_values($twoDimensionalArray));

On PHP version 7.3 or lower, you will see the following if the input array is empty:

$twoDimensionalArray = [];
array_merge(...$twoDimensionalArray);
// Warning:  array_merge() expects at least 1 parameter, 0 given.

You can solve this by passing a single empty array as an extra argument:

array_merge([], ...$twoDimensionalArray);

A general solution for arbitrarily nested arrays 

function flatten_array(array $array): array {
    $recursiveArrayIterator = new RecursiveArrayIterator(
        $array,
        RecursiveArrayIterator::CHILD_ARRAYS_ONLY
    );
    $iterator = new RecursiveIteratorIterator($recursiveArrayIterator);

    return iterator_to_array($iterator, false);
}

For arbitrarily nested arrays we make use of the built-in iterators RecursiveArrayIterator and RecursiveIteratorIterator. It is important to note that we have to pass the flag CHILD_ARRAYS_ONLY to the ArrayIterator, otherwise it would iterate over public properties of objects as well, which you probably never want:

class Person
{
    public function __construct(public $name) {}
}

$array = [
    new Person('Jake'),
    new Person('Charles')
];


flatten_array($array);
// Without CHILD_ARRAYS_ONLY:
//
// [
//     0 => 'Jake',
//     1 => 'Charles'
// ]
//
// With CHILD_ARRAYS_ONLY:
//
// [
//     0 => Person Object,
//     1 => Person Object
// ]

Lastly, you can play around with the second argument of iterator_to_array, which indicates whether or not keys should be preserved. If you pass false, keys will not be preserved and the result will be a simple list. If you pass true (which is the default), keys will be preserved, meaning duplicate entries will be lost. Both approaches have their uses.

$employees = [
    ['name' => 'Jake Peralta'],
    ['name' => 'Charles Boyle']
];

flatten_array($employees);
// [
//     0 => 'Jake Peralta',
//     1 => 'Charles Boyle,
// ]

flatten_array_preserve_keys($employees);
// [
//     'name' => 'Charles Boyle'
// ]

Extracting values with a specific key 

array_column is especially useful to extract all values with a given key from an array:

$array = [
    ['id' => 123, 'name' => 'aaa', 'class' => 'x'],
    ['id' => 124, 'name' => 'bbb', 'class' => 'x'],
    ['id' => 345, 'name' => 'ccc', 'class' => 'y'],
];

array_column($array, 'id');
// [123, 124, 345]

The function accepts an optional third parameter that specifies which column to use as the index:

array_column($array, 'name', 'id');
// [123 => 'aaa', 124 => 'bbb', 345 => 'ccc']

It handles objects as well, as long as the properties are public:

class Person
{
    public function __construct(public int $id, public string $name) {}
}

$objects = [
    new Person(12, 'John'),
    new Person(34, 'Jane')
];

array_column($objects, 'name', 'id');
// [12 => 'John', 34 => 'Jane']

While not useful in the context of flattening arrays, there’s another neat trick you can do with array_column: by passing null as the second argument, the array will be reindexed based on the third parameter:

$array = [
    ['id' => 123, 'name' => 'aaa', 'class' => 'x'],
    ['id' => 124, 'name' => 'bbb', 'class' => 'x'],
    ['id' => 345, 'name' => 'ccc', 'class' => 'y'],
];

array_column($array, null, 'id');
// [
//    123 => ['id' => 123, 'name' => 'aaa', 'class' => 'x'],
//    124 => ['id' => 124, 'name' => 'bbb', 'class' => 'x'],
//    345 => ['id' => 345, 'name' => 'ccc', 'class' => 'y'],
// ]

  1. Credit goes to @strayobject for suggesting array_column↩︎

Tags: PHP

Related: Accessing private properties in PHP