PHP - Convert multidimensional array to 2D array with dot notation keys

Solution 1:

teh codez

$ritit = new RecursiveIteratorIterator(new RecursiveArrayIterator($myArray));
$result = array();
foreach ($ritit as $leafValue) {
    $keys = array();
    foreach (range(0, $ritit->getDepth()) as $depth) {
        $keys[] = $ritit->getSubIterator($depth)->key();
    }
    $result[ join('.', $keys) ] = $leafValue;
}

output

Array
(
    [key1] => value1
    [key2.subkey] => subkeyval
    [key3] => value3
    [key4.subkey4.subsubkey4] => subsubkeyval4
    [key4.subkey4.subsubkey5] => subsubkeyval5
    [key4.subkey5] => subkeyval5
)

demo: http://codepad.org/YiygqxTM

I need to go, but if you need an explanation of that tomorrow, ask me.

Solution 2:

This will handle an arbitrary level of nesting:

<? //PHP 5.4+
$dotFlatten = static function(array $item, $context = '') use (&$dotFlatten){
    $retval = [];
    foreach($item as $key => $value){
        if (\is_array($value) === true){
            foreach($dotFlatten($value, "$context$key.") as $iKey => $iValue){
                $retval[$iKey] = $iValue;
            }
        } else {
            $retval["$context$key"] = $value;
        }
    }
    return $retval;
};

var_dump(
    $dotFlatten(
        [
            'key1' => 'value1',
            'key2' => [
                'subkey' => 'subkeyval',
            ],
            'key3' => 'value3',
            'key4' => [
                'subkey4' => [
                    'subsubkey4' => 'subsubkeyval4',
                    'subsubkey5' => 'subsubkeyval5',
                ],
                'subkey5' => 'subkeyval5',
            ],
        ]
    )
);
?>

Solution 3:

There is already the answer with RecursiveIteratorIterator. But here is a more optimal solution, that avoids using nested loops:

$iterator = new RecursiveIteratorIterator(
    new RecursiveArrayIterator($arr),
    RecursiveIteratorIterator::SELF_FIRST
);
$path = [];
$flatArray = [];

foreach ($iterator as $key => $value) {
    $path[$iterator->getDepth()] = $key;

    if (!is_array($value)) {
        $flatArray[
            implode('.', array_slice($path, 0, $iterator->getDepth() + 1))
        ] = $value;
    }
}

There are several points need to be made here. Notice the use of RecursiveIteratorIterator::SELF_FIRST constant here. It is important as the default one is RecursiveIteratorIterator::LEAVES_ONLY which wouldn't let us access all keys. So with this constant set, we start from the top level of an array and go deeper. This approach lets us store the history of keys and prepare the key when we rich leaf using RecursiveIteratorIterator::getDepth method.

Here is a working demo.