Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

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%';
share|improve this question
    
What have you tried? –  Dogbert Mar 9 '12 at 14:49
    
I don't understand why you're trying to rewrite the PHP syntax. –  Catfish Mar 9 '12 at 14:50
    
I'm writing a markup language and chose to parse it with PHP. –  Bryan Potts Mar 9 '12 at 15:02

5 Answers 5

up vote 9 down vote accepted

Try this number...

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

    while ($key = array_shift($keys)) {
        $arr = &$arr[$key];
    }

    $arr = $value;
}

CodePad.

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

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

CodePad.

share|improve this answer
    
This works flawlessly. Looks like the optimal solution as well. Thanks a lot! –  Bryan Potts Mar 9 '12 at 15:19
    
for the record, this would be the complementary variant: stackoverflow.com/a/10424516/1388892 –  Adrian Föder Mar 17 '14 at 10:32

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);
share|improve this answer
    
Not quite. I need the multi-dimensional index, which the ini parser does not do. –  Bryan Potts Mar 9 '12 at 15:08

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
share|improve this answer
    
This is a great idea, thanks. –  Bryan Potts Mar 14 '12 at 19:22

You can use this function to achieve desired result. It uses php eval() function, despite on there historically a lot of doubts related to it

function ini($file) {

    // Parse ini file
    $ini = parse_ini_file($file, true);

    // Foreach section
    foreach ($ini as $sectionName => $sectionParamA) {

        // Foreach param within section
        foreach ($sectionParamA as $sectionParamK => $sectionParamV) {

            // If param name contains '.'
            if (preg_match('/\./', $sectionParamK)) {

                // Get the levels
                $levelA = explode('.', $sectionParamK);

                // Declare/reset the $depth array
                $depth = array();

                // Foreach level except last level
                for ($i = 0; $i < count($levelA) - 1; $i++) {

                    // Build the list of parent array dimensions
                    for ($d = 0; $d < count($depth); $d++)
                        $depth[$d] = str_replace('$i', '$i-' . ($i - $d), $depth[$d]);

                    // Append current array dimension
                    $depth[] = '[$levelA[$i]]';

                    // Check if current-level value is already an array
                    // (so it mean this it contains key-value pairs) and if so -
                    if (eval('return is_array($sectionParamA' . implode('', $depth) . ');')) {

                        // If the value of the param at certain-depth-level dimension is not yet an instance
                        // of ArrayObject class
                        if (!eval('return is_array($sectionParamA' . implode('', $depth) . '[' . $levelA[$i+1]. ']);'))

                            // Setup it
                            eval('$sectionParamA' . implode('', $depth) . '[' . $levelA[$i+1]. '] = $sectionParamA[$sectionParamK];');

                        // Else
                    } else {

                        // Setup the param value as a value of certain-depth-level dimension key within array
                        eval('$sectionParamA' . implode('', $depth) . ' = array(
                            $levelA[$i+1] => $sectionParamA[$sectionParamK]
                        );');
                    }
                }

                // Unset orinal param name and it's value, as now param name was parsed and converted
                // to nesting arrays
                unset($sectionParamA[$sectionParamK]);
            }
        }

        // Update section
        $ini[$sectionName] = $sectionParamA;
    }

    // Return
    return $ini;
}
share|improve this answer
    
I've found a better solution here link –  Pavel Perminov May 4 '14 at 14:00

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);
share|improve this answer
1  
This might be the worst code I've seen in my life. –  Bryan Potts Mar 9 '12 at 15:21
    
Agreed, but "quick and dirty" was the tagline ;) –  Lloyd Watkin Mar 9 '12 at 15:23
    
This a good alternative solution. However, it can only assign a string. –  alex Mar 9 '12 at 15:29
    
@BryanPotts -you didn't see Pavel's code above I guess. –  Yehosef Apr 27 at 7:52

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.