Bogdan
Bogdan

Reputation: 713

Config Class using ArrayObject

I've been looking a way to implement ArrayObject Class to store application configs and i found this implementation in the php manual ( one of the comments )

<?php
 use \ArrayObject;


/**
 *  Singleton With Configuration Info
 */
class Config extends ArrayObject
{
    /**
     *
     * Overwrites the ArrayObject Constructor for
     * Iteration throught the "Array". When the item
     * is an array, it creates another static() instead of an array
     */
    public function __construct(Array $array)
    {
        $this->setFlags(ArrayObject::ARRAY_AS_PROPS);
        foreach($array as $key => $value)
        {
            if(is_array($value))
            {
                $value = new static($value);
            }
            $this->offsetSet($key, $value);
        }
    }

    public function __get($key)
    {
        return $this->offsetGet($key);
    }

    public function __set($key, $value)
    {
        $this->offsetSet($key, $value);
    }
    /**
     * Returns Array when printed (like "echo array();")
     * Instead of an Error
     */
    public function __ToString()
    {
        return 'Array';
    }
}

Usage:

$config = new Config\Config($settings);
$config->uri = 'localhost'; // works
$config->url->uri = 'localhost'; // doesn't work
print_r($config);

I've tried adding to this class the __get and __set it works fine for a simple array but when it comes to multidimensional arrays well ... things are different. I'm getting an error saying that the index is not defined. Can someone help me out please i tried everything i knew googled a lot about it and i didn't find the solution.

I have solved the problem with this class. Later on i will post here a fully working example maybe someone will need it. Thank you everyone for taking time and reading this thread

Update: So what do you think guys? What improvements... changes should i make ?

    public function __construct(Array $properties)
    {
        $this->populateArray($properties);
    }

    private function populateArray(Array $array)
    {
        if(is_array($array))
        {
            foreach($array as $key => $value)
            {
                $this->createProperty($key, $value);
            }
        }
        unset($this->properties);
    }

    private function createProperty($key, $value)
    {
        is_array($value) ? 
            $this->offsetSet($key, $this->createComplexProperty($value))
            : $this->offsetSet($key, $value);
    }

    private function createComplexProperty(Array $array)
    {
        return new Config($array);
    }

    private function createPropertyIfNone($key)
    {
        if($this->offsetExists($key))
            return;

        $this->createProperty($name, array()); 
    }

    public function __get($key)
    {
        $this->createPropertyIfNone($key);
        return $this->offsetGet($key);
    }

    public function __set($key, $value)
    {
        $this->createProperty($key, $value);
    }

    public function __ToString()
    {
        return (string) $value;
    }
}

Upvotes: 3

Views: 860

Answers (1)

Reactgular
Reactgular

Reputation: 54771

If you want to assume a non-existing key is an array, then this should work.

public function __get($key)
{
    if(!$this->offsetExists($key))
    {
         $this->offsetSet($key,new Array());
    }
    return &$this->offsetGet($key);
}

Usage:

$config = new Config\Config($settings);
$config->url['uri'] = 'localhost';
print_r($config);

EDIT:

Not sure if you have to return a reference or not for this to work.

    return &$this->offsetGet($key);

or this

    return $this->offsetGet($key);

Upvotes: 2

Related Questions