Max Rosenbaum
Software developer
Thursday, 8 April 2021
Flatten multi-dimensional array in PHP 7
It's not too often in the PHP world you'll need to flatten arrays. When you do, map operations and array functions are a bit clunky. I had a look for a solution on stackoverflow and the answers didn't have quite what I was after. After diving headlong into the documentation, here are two solutions for flattening a multi-dimensional array in PHP 7.
Only one level, no key preservation
If the source array you are working with is only one level deep, (an array of arrays) a simple way to merge them
together without key preservation is using the array_merge
and the splat operator in PHP 7;
array_merge(...$multiDimensionalArray)
Multilevel, with key preservation
Below is a recursive implementation for supporting arrays of any depth and retaining the keys of the values. PHP won't optimise for tail recursion, so in very large arrays you might get a stackoverflow.
A big weakness of array
in PHP is not having a native way to handle duplicate keys in its internal data structures. In this solution we
drop a key if we find a duplicate. Alternatively it would be possible to append a random string onto the end of a key,
but if data is encoded into the keys this would get very messy very fast. Unfortunately there is no good way to handle this
problem in a pure flatmap solution.
Here it is in action on 3v4l.
$testArray = [
['lev 1' => 'lev 1'],
['lev 2', 'lev 2 - 1', ['lev 2 - 2'], ['Key preserved' => 'lev 2 - 3']],
[['lev 3 - 1', 'lev 3 - 2', 'lev 3 - 3']],
[[[888 => 'lev 4']]]
];
// $element must initially be an array. Anything that is not an array will just return the accumulator.
function flatten($element, $accum = []) {
// If we don't have an array, return the accumulator.
if (!is_array($element)) {
return $accum;
}
foreach($element as $key => $e) {
// Check if the elements are an array or not. If not, append the accumulator with a key and value.
if (!is_array($e)) {
// Check that the key does not already exist, if it does we have to simply append to preserve values.
if (array_key_exists($key, $accum)) {
$accum[] = $e;
} else {
$accum[$key] = $e;
}
continue;
}
// Only recurse when we have an array.
// We pass in the accumulator and any values further down then hierarchy.
$vals = flatten($e, $accum);
// We might get an empty array back if there was an array of arrays.
if (!empty($vals)) {
// We don't append our values here, we override the accumulator. The appending happens above when $e is not an
// array.k
$accum = $vals;
}
}
// Return values of this array and all child arrays.
return $accum;
}
flatten($testArray);