1

I wrote a custom framework. Which uses the .ini type of config file.

Say, if I have a constant assigned in the .ini file as

[production]
db.mongo.hostName = localhost

I am currently parsing this through parse_ini_file() function.

The result will be

$config[production][db.mongo.hostname] = "localhost";

Now I wanna turn this array to an object which should go like

$config->db->mongo->hostname

I tried exploding it with '.', but then I am stuck with forming this as an above iterative object.

Can someone please help me with this.

hakre
  • 193,403
  • 52
  • 435
  • 836
Karthik
  • 1,091
  • 1
  • 13
  • 36
  • 1
    Exact Duplicate: http://stackoverflow.com/questions/1869091/convert-array-to-object-php?rq=1 – Riz Jun 25 '12 at 11:36
  • 1
    Zend_Config_Ini already does this quite nicely. – Jon Skarpeteig Jun 25 '12 at 11:36
  • Jon, Thank you, I already seen Zend ini parsers, Where they follow certain pattern which it parse. Its a massive function. The main reason I am moving from zend is that its too much for the application that I am doing... – Karthik Jun 25 '12 at 11:43
  • Shadyyx, If I get proper answers I will. Thank you... – Karthik Jun 25 '12 at 11:44
  • http://www.richardcastera.com/blog/php-convert-array-to-object-with-stdclass – D-Rock Jun 25 '12 at 11:36
  • Thanks Gordon... None of them reads the question properly.. I already visited all the links posted here. but it does not give exactly what I wanted... – Karthik Jun 25 '12 at 11:41
  • 1
    What is so bad with [`$config->{db.mongo.hostname}`](http://codepad.org/BNma5MY7)? – hakre Jun 25 '12 at 13:33
  • 1
    possible duplicate of [String with array structure to Array](http://stackoverflow.com/questions/8537148/string-with-array-structure-to-array) – hakre Jun 25 '12 at 13:34
  • @hakre I thought the readability is so much better. I do loads of spelling errors in variables. When it is a proper object we can pin point which sub object is not available through php errors. If it is like $config->{db.mongo.hostname} its gonna say object $config doesnt have db.mongo.hostname. Where as if it is other way around. its gonna say object $config->db->mongo doesnt have hostname something along those lines. Which I thought is better. – Karthik Jun 25 '12 at 13:50
  • @hakre thx for editing. It looks better now.. – Karthik Jun 25 '12 at 13:51

3 Answers3

3

The following is a rudimentary class that has a single function to import the ini array as you have specified it:

/**
 * Config "Class"
 * @link http://stackoverflow.com/q/11188563/367456
 */
class Config
{
    public function __construct(array $array = array())
    {
        $this->importIniArray($array);
    }

    public function importIniArray(array $array)
    {
        foreach ($array as $key => $value) {
            $rv = &$this;
            foreach (explode('.', $key) as $pk) {
                isset($rv->$pk) || $rv->$pk = new stdClass;
                $rv = &$rv->$pk;
            }
            $rv = $value;
        }
    }
}

I only added the __construct function because you re-use the variable. Usage:

$config = parse_ini_file($path);

$config = new Config($config['production']);

print_r($config);

Exemplary output:

Config Object
(
    [db] => stdClass Object
        (
            [mongo] => stdClass Object
                (
                    [hostname] => localhost
                    [user] => root
                )

        )

)

Edit: You can also solve the problem to locate the array member at time of access. I compiled a little example that behaves similar and it explodes nothing. I called it DynConfig because as you'll see it's dynamic (or magic):

$config = new DynConfig($config['production']);
var_dump($config);
echo $config->db->mongo->hostname; # localhost

The var_dump shows that the array is just preserved internally:

object(DynConfig)#1 (1) {
  ["array":"DynConfig":private]=>
  array(2) {
    ["db.mongo.hostname"]=>
    string(9) "localhost"
    ["db.mongo.user"]=>
    string(4) "root"
  }
}

So how does this work? Each time you access a property, either a key exists or the prefix is extended and the same object is returned. That's in the __get function:

/**
 * Config "Class"
 * @link http://stackoverflow.com/q/11188563/367456
 */
class DynConfig
{
    private $array;

    public function __construct($array)
    {
        $this->array = $array;
    }

    public function __get($name)
    {
        static $prefix = '';
        $k = $prefix .= $name;
        if (isset($this->array[$k])) {
            $prefix = '';
            return $this->array[$k];
        }
        $prefix .= '.';
        return $this;
    }
}

However, this is of experimental nature. The first suggestion is much more direct and much easier to deal with. Keep in mind that your config object should be really simple, it just needs to store some values and that's it.

hakre
  • 193,403
  • 52
  • 435
  • 836
  • I am already using php magic functions and singleton pattern in my Config class... Thank you... This is so cool... DynConfigAccess nis so cool.. – Karthik Jun 25 '12 at 14:40
  • 1
    No, actually I made a mistake, this does not need a second class. I edit the answer. And don't use the singleton antipattern, also magic is not really helpful in the long run. you will introduce problems. – hakre Jun 25 '12 at 14:56
2

You can done it as below

function assignTo($obj,$keys,$value)
{
        if(count($keys) > 1)   
        {                      
                $h = array_shift($keys);        
                $obj->$h = $obj->$h ? $obj->$h : new stdClass();
                assignTo($obj->$h,$keys,$value);
        }                      
        else                   
        {                      
                $obj->$keys[0] = $value;        
        }
}
$config['production']['db.mongo.hostname'] = "localhost";
$config['production']['db.mongo.password'] = "1234567";
$config['production']['version'] = "1.0";

$object = new stdClass();      
foreach($config['production'] as $key=>$value)
{
        assignTo($object,explode('.',$key),$value);
}                              
print_r($object); 

Which would output:

stdClass Object
(
    [db] => stdClass Object
        (
            [mongo] => stdClass Object
                (
                    [hostname] => localhost
                    [password] => 1234567
                )

        )

    [version] => 1.0
)
Lake
  • 813
  • 4
  • 6
  • 1
    @Lake: In case you want to learn some tricks, take a look at this duplicate question and it's answers: http://stackoverflow.com/q/8537148/367456 – hakre Jun 25 '12 at 13:35
  • @hakre It is the duplicate... But to be honest for all the key words I searched I couldn't end up in that page. – Karthik Jun 25 '12 at 13:44
  • 1
    @Karthik: Sure, it's hard to find stuff sometimes. The most important stuff is to have it cross-linked I'd say, it's not even and exact "exact" duplicate, because that one is about arrays and yours objects (however those two are close in PHP). – hakre Jun 25 '12 at 13:48
0
// assuming $var is a multidimensional array
$obj = json_decode (json_encode ($var), FALSE);
Edson Medina
  • 9,862
  • 3
  • 40
  • 51