在PHP中将点语法(如“this.that.other”)转换为多维数组

xxe27gdn  于 2023-03-16  发布在  PHP
关注(0)|答案(9)|浏览(123)

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

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

会和

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

s8vozzvw1#

试试这个号码...

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

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

    $arr = $value;
}

CodePad
它将遍历键(默认情况下用.分隔)以到达最终属性,然后对值进行赋值。
如果某些关键点不存在,则会创建它们。

s3fp2yjn

s3fp2yjn2#

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

使用点表示法存储在数组中的方法

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

很简单

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

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

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

你可以在文件里查一下

如果您需要使用点标记法获取数据该过程稍长,但由array_get()提供,该函数可转换为该函数(实际上链接的源代码显示了所有与helper数组相关的类)

使用点标记法从数组中读取的方法

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

如您所见,它使用了两个子方法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;
}

还有

/**
 * 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);
}

它最后使用的东西,但你可能可以跳过它,是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;
    }
}
xmd2e60i

xmd2e60i3#

您可以使用此函数将点标记阵列转换为多维阵列。

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

示例:

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

print_r(flattenToMultiDimensional($array));

输出:

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

        )

)
clj7thdc

clj7thdc4#

我建议使用dflydev/dot-access-data
如果您不熟悉Composer的使用,请访问https://getcomposer.org/以了解相关介绍,这样您就可以下载并自动加载包作为项目的依赖项。
一旦有了包,就可以将多维数组加载到Data对象中:

use Dflydev\DotAccessData\Data;

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

并使用点标记法访问值:

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

lndjwyie5#

十多年过去了,还没有人真正回答过将string x 转换为array y 的问题。公认的答案是最接近的,但仍然假设一个现有的数组,并需要一个单独的值。
我需要在一个快速的一次性脚本中完成这一操作,因此我的回答满足了问题的要求,同时允许对分隔符进行一些定制和基本的错误检查:

<?php
function dotKvToArray(string $kv, string $kv_sep = "=", string $arr_sep = "."): array
{
    // split on the equal sign (if it's there)
    [$keystring, $value] = str_contains($kv, $kv_sep)
        ? explode($kv_sep, $kv)
        : [$kv, null];

    // return early for empty string
    if (empty(trim($keystring))) {
        return [];
    }

    // reverse the array keys and assign the array to each sequentially
    // the first one will get the value assigned instead
    foreach (array_reverse(explode($arr_sep, trim($keystring))) as $key) {
        $ret = [$key => $ret ?? trim($value)];
    }

    // return the array, or an empty array in case somehow the loop was missed
    return $ret ?? [];
}

$source = dotKvToArray("s1.t1.column.1 = size:33%");
echo json_encode($source);

输出:

{"s1":{"t1":{"column":{"1":"size:33%"}}}}
wlsrxk51

wlsrxk516#

虽然pasrse_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
sbtkgmzw

sbtkgmzw7#

我找到了适合我的解决方案:将平面PHP数组转换为基于数组键的嵌套数组,因为我有一个基于.ini文件的数组,具有不同的键,所以我对该脚本进行了微小的修改,使其适合我。
我的数组看起来像这样:

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

根据要求,这是我描述的适用于我的代码:

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

这是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
)

这是上面代码的结果:

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
                )

        )
)
1tu0hz3e

1tu0hz3e8#

我非常确定您尝试这样做是为了存储一些配置数据或类似数据。
我强烈建议您将此文件保存为.ini,然后使用parse_ini_file()函数将配置数据更改为多维数组。

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

wlzqhblo9#

又快又脏...

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

相关问题