Convert dot syntax like "this.that.other" to multi-dimensional array in PHP

Try this number...

function assignArrayByPath(&$arr, $path, $value, $separator='.') {
    $keys = explode($separator, $path);

    foreach ($keys as $key) {
        $arr = &$arr[$key];
    }

    $arr = $value;
}

CodePad

It will loop through the keys (delimited with . by default) to get to the final property, and then do assignment on the value.

If some of the keys aren't present, they're created.


FYI In Laravel we have a array_set() helper function which translates in this function

Method to store in an array using dot notation

/**
 * Set an array item to a given value using "dot" notation.
 *
 * If no key is given to the method, the entire array will be replaced.
 *
 * @param  array   $array
 * @param  string  $key
 * @param  mixed   $value
 * @return array
 */
public static function set(&$array, $key, $value)
{
    if (is_null($key)) {
        return $array = $value;
    }

    $keys = explode('.', $key);

    while (count($keys) > 1) {
        $key = array_shift($keys);

        // If the key doesn't exist at this depth, we will just create an empty array
        // to hold the next value, allowing us to create the arrays to hold final
        // values at the correct depth. Then we'll keep digging into the array.
        if (! isset($array[$key]) || ! is_array($array[$key])) {
            $array[$key] = [];
        }

        $array = &$array[$key];
    }

    $array[array_shift($keys)] = $value;

    return $array;
}

It's simple as

$array = ['products' => ['desk' => ['price' => 100]]];

array_set($array, 'products.desk.price', 200);

// ['products' => ['desk' => ['price' => 200]]]

You may check it in the docs

If you need to instead get the data using dot notation the process is a bit longer, but served on a plate by array_get() which translates to this function (actually the linked source shows you all the helper array related class)

Method to read from an an array using dot notation

/**
 * Get an item from an array using "dot" notation.
 *
 * @param  \ArrayAccess|array  $array
 * @param  string  $key
 * @param  mixed   $default
 * @return mixed
 */
public static function get($array, $key, $default = null)
{
    if (! static::accessible($array)) {
        return value($default);
    }
    if (is_null($key)) {
        return $array;
    }
    if (static::exists($array, $key)) {
        return $array[$key];
    }
    if (strpos($key, '.') === false) {
        return $array[$key] ?? value($default);
    }
    foreach (explode('.', $key) as $segment) {
        if (static::accessible($array) && static::exists($array, $segment)) {
            $array = $array[$segment];
        } else {
            return value($default);
        }
    }
    return $array;
}

As you can see, it uses two submethods, accessible() and exists()

/**
 * Determine whether the given value is array accessible.
 *
 * @param  mixed  $value
 * @return bool
 */
public static function accessible($value)
{
    return is_array($value) || $value instanceof ArrayAccess;
}

And

/**
 * Determine if the given key exists in the provided array.
 *
 * @param  \ArrayAccess|array  $array
 * @param  string|int  $key
 * @return bool
 */
public static function exists($array, $key)
{
    if ($array instanceof ArrayAccess) {
        return $array->offsetExists($key);
    }
    return array_key_exists($key, $array);
}

Last thing it uses, but you can probably skip that, is value() which is

if (! function_exists('value')) {
    /**
     * Return the default value of the given value.
     *
     * @param  mixed  $value
     * @return mixed
     */
    function value($value)
    {
        return $value instanceof Closure ? $value() : $value;
    }
}

You can use this function to convert dot notation arrray to multidimensional array.

function flattenToMultiDimensional(array $array, $delimiter = '.')
{
    $result = [];
    foreach ($array as $notations => $value) {
        // extract keys
        $keys = explode($delimiter, $notations);
        // reverse keys for assignments
        $keys = array_reverse($keys);

        // set initial value
        $lastVal = $value;
        foreach ($keys as $key) {
            // wrap value with key over each iteration
            $lastVal = [
                $key => $lastVal
            ];
        }
        
        // merge result
        $result = array_merge_recursive($result, $lastVal);
    }

    return $result;
}

Example:

$array = [
    'test.example.key' => 'value'
];

print_r(flattenToMultiDimensional($array));

Output:

Array
(
    [test] => Array
        (
            [example] => Array
                (
                    [key] => value
                )

        )

)

I would suggest using dflydev/dot-access-data.

If you're not familiar with using Composer, head over to https://getcomposer.org/ for an introduction so that you can download and autoload the package as as dependency for your project.

Once you have the package, you can load a multi-dimensional array into a Data object:

use Dflydev\DotAccessData\Data;

$data = new Data(array(
  's1' => array(
    't1' => array(
      'column' => array(
        '1' => 'size:33%',
      ),
    ),
  ),
);

And access the values using dot notation:

$size = $username = $data->get('s1.t1.column.1');