在 PHP 中将像“this.that.other”这样的点语法转换为多维数组

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9635968/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 07:19:44  来源:igfitidea点击:

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

phpparsing

提问by Bryan Potts

Just as the title implies, I am trying to create a parser and trying to find the optimal solution to convert something from dot namespace into a multidimensional array such that

正如标题所暗示的那样,我正在尝试创建一个解析器并试图找到将某些内容从点命名空间转换为多维数组的最佳解决方案,以便

s1.t1.column.1 = size:33%

would be the same as

将与

$source['s1']['t1']['column']['1'] = 'size:33%';

回答by alex

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.

如果某些键不存在,则会创建它们。

回答by phaberest

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

仅供参考在 Laravel 中,我们有一个array_set()辅助函数可以在此函数中进行翻译

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 notationthe 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)

如果您需要使用点表示法获取数据,则该过程会更长一些,但会在array_get()转换为该函数的盘子上提供(实际上,链接的源会向您显示所有与辅助数组相关的类)

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()

如您所见,它使用了两个子方法,accessible()以及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

它使用的最后一件事,但你可能可以跳过它,value()就是

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;
    }
}

回答by grasmash

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

我建议使用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.

如果您不熟悉 Composer 的使用,请前往https://getcomposer.org/获取介绍,以便您可以下载并自动加载包作为项目的依赖项。

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

获得包后,您可以将多维数组加载到 Data 对象中:

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');

回答by Starx

Although pasrse_ini_file() can also bring out multidimensional array, I will present a different solution. Zend_Config_Ini()

虽然 passrse_ini_file() 也可以带出多维数组,但我会提出一个不同的解决方案。Zend_Config_Ini()

$conf = new Zend_COnfig_Ini("path/to/file.ini");
echo $conf -> one -> two -> three; // This is how easy it is to do so
//prints one.two.three

回答by orjtor

I found a solution that worked for me at: Convert Flat PHP Array to Nested Array based on Array Keysand since I had an array based on an .ini file with different keys I made a tiny modification of that scriptand made work for me.

我找到了一个对我有用的解决方案:Convert Flat PHP Array to Nested Array based on Array Keys,因为我有一个基于 .ini 文件的数组,带有不同的键,我对该脚本进行了微小的修改并为我工作。

My array looked like this:

我的阵列看起来像这样:

[resources.db.adapter] => PDO_MYSQL
[resources.db.params.host] => localhost
[resources.db.params.dbname] => qwer
[resources.db.params.username] => asdf
...

On request, this is the code that I described was working for me:

根据要求,这是我描述的代码对我有用:

<?php
echo "remove the exit :-)"; exit;
$db_settings = parse_ini_file($_SERVER['DOCUMENT_ROOT'].'/website/var/config/app.ini');

echo "<pre>";
print_r($db_settings);
echo "</pre>";

$resources = array();

foreach ($db_settings as $path => $value) {
  $ancestors = explode('.', $path);
  set_nested_value($resources, $ancestors, $value);
}
echo "<pre>";
print_r($resources);
echo "</pre>";

/**
 * Give it and array, and an array of parents, it will decent into the
 * nested arrays and set the value.
 */
function set_nested_value(array &$arr, array $ancestors, $value) {
  $current = &$arr;
  foreach ($ancestors as $key) {

    // To handle the original input, if an item is not an array, 
    // replace it with an array with the value as the first item.
    if (!is_array($current)) {
      $current = array( $current);
    }

    if (!array_key_exists($key, $current)) {
      $current[$key] = array();
    }
    $current = &$current[$key];
  }

  $current = $value;
}

This is the source of the .ini file read by the parse_ini_file():

这是 parse_ini_file() 读取的 .ini 文件的来源:

Array
(
    [resources.db.adapter] => PDO_MYSQL
    [resources.db.params.host] => localhost
    [resources.db.params.dbname] => dbname
    [resources.db.params.username] => dbname_user
    [resources.db.params.password] => qwerqwerqwerqwer
    [resources.db.params.charset] => utf8
    [externaldb.adapter] => PDO_MYSQL
    [externaldb.params.host] => localhost
    [externaldb.params.dbname] => dbname2
    [externaldb.params.username] => dbname_user2
    [externaldb.params.password] => qwerqwerwqerqerw
    [externaldb.params.charset] => latin1
)

This is the outcome of the code above:

这是上面代码的结果:

Array
(
    [resources] => Array
        (
            [db] => Array
                (
                    [adapter] => PDO_MYSQL
                    [params] => Array
                        (
                            [host] => localhost
                            [dbname] => dbname
                            [username] => dbname_user
                            [password] => qwerqwerqwerqwer
                            [charset] => utf8
                        )

                )

        )

    [externaldb] => Array
        (
            [adapter] => PDO_MYSQL
            [params] => Array
                (
                    [host] => localhost
                    [dbname] => dbname2
                    [username] => dbname_user2
                    [password] => qwerqwerwqerqerw
                    [charset] => latin1
                )

        )
)  

回答by Starx

I am pretty sure you are trying to do this to store some configuration data or similar.

我很确定您正在尝试这样做来存储一些配置数据或类似数据。

I highly suggest you to save such file as .iniand use parse_ini_file()function to change the configuration data into a multidimensional array. As simple as this

我强烈建议您将此类文件另存为.ini并使用parse_ini_file()函数将配置数据更改为多维数组。就这么简单

$confArray = parse_ini_file("filename.ini"); 
var_dump($confArray);

回答by Lloyd Watkin

Quick and dirty...

又快又脏...

<?php

$input = 'one.two.three = four';

list($key, $value) = explode('=', $input);
foreach (explode('.', $key) as $keyName) {
    if (false === isset($source)) {
        $source    = array();
        $sourceRef = &$source;
    }
    $keyName = trim($keyName);
    $sourceRef  = &$sourceRef[$keyName];
}
$sourceRef = $value;
unset($sourceRef);
var_dump($source);