Convert dot syntax like “this.that.other” to multi

2019-01-06 15:06发布

This question already has an answer here:

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

标签: php parsing
7条回答
一纸荒年 Trace。
2楼-- · 2019-01-06 15:51

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.

查看更多
劳资没心,怎么记你
3楼-- · 2019-01-06 15:55

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

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

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
                )

        )
)  
查看更多
别忘想泡老子
4楼-- · 2019-01-06 15:56

Although pasrse_ini_file() can also bring out multidimensional array, I will present a different solution. 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
查看更多
干净又极端
5楼-- · 2019-01-06 16:02

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 .ini and use parse_ini_file() function to change the configuration data into a multidimensional array. As simple as this

$confArray = parse_ini_file("filename.ini"); 
var_dump($confArray);
查看更多
爷、活的狠高调
6楼-- · 2019-01-06 16:06

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');
查看更多
Anthone
7楼-- · 2019-01-06 16:06

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);
查看更多
登录 后发表回答