Paco Orozco
Paco Orozco

Reputation: 679

What's the best way (coding-wise) to get config variables in PHP application

I've been searching and reading a lot about how is the best way (code-wise) to get application's config variables in a PHP environment. After that I've sum up that are two more generally used ways to manage with configuration files and variables.

But I'm a bit confused about it, one, method 1, is using an static class. The other one, method 2 is using an instantiable class.

First one is worse to unit testing than second one. And It's similar to a global variable. Isn't it?

Second one need a global varaible in order to use instantiated object.

I'll try to explain myself.

Facts: - App's settings are kept on a INI file. - This INI file has sections, in order to maintain configuration variables. - I've got only one INI file. - Class do some validation of configuration file. - Code examples below aren't complete, it's only a sample to ilustrate my question.

Method 1: Using static class

This method use a Config static class, it uses static because only one Config object would be used in all application.

Code example:

class Config
{
    static private $data;

    static public function load($configFile) {
        self::$data = parse_ini_file($configFile, true, INI_SCANNER_RAW)
    }

    static public get($key) {
         // code stuff to deal with sections and keys, but basically
         return self::$data[$key];
    }
}

On my application I create the static object, once, using this code:

\Config::load('/where/is/my/ini/file.ini');

In this case, every time i want to get a value i use:

$host = \Config::get('database.host');

function example() 
{
    echo \Config::get('another.value');
}

Method 2: Using instable object

In this scenario I use a Config class object.

Code example:

class Config {
    private $data = array();

    public function __construct($configFile) {
        $this->data = parse_ini_file($configFile, true, INI_SCANNER_RAW)
    }

    public function get($key) {
        // code stuff to deal with sections and keys, but basically
        return $this->data[$key];
    }

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

To use it, first we need to instantiate an object and then get the value:

$settings = new \Config('/where/is/my/ini/file.ini');

$host = $settings->get('database.host');
echo $settings->database->host;

But when I need this value inside a function, I need to use a global variable, which I think isn't right at all:

global $settings;

$settings = new \Config('/where/is/my/ini/file.ini');

function example() 
{
    global $settings;
    echo $settings->get('another.value');
}    

What I miss leading?

Thanks in advance to read and answer my question.

Upvotes: 2

Views: 2864

Answers (2)

The Alpha
The Alpha

Reputation: 146269

Simply you may also use a php file to keep your configurations for example, config.php and then you may use require from anywhere to get it:

// config.php
<?php
    return array(
        'database' => 'mysql',
        'pagination' => array(
            'per_page' => 10
    )
);

Then use:

$config = require "path/to/config.php";
print_r($config);

You may use this with a function too, for example:

function someFunc()
{
    $config = require "path/to/config.php";
    // Now use it
}

You may create a class to get the the configurations using a method like, for example:

class Config {

    static function get()
    {
        $config = require "path/to/config.php";
        return $config;
    }
}

So you may use:

$config = Config::get();

This is just another simple idea, you may extend it to use it like:

$perPage = Config::get('pagination.per_page');

Just need to add some more code to make it working like this way, give it a try.

Update:

Btw, I built a package named IConfig for my own MVC Framework back in 2013, it's also available on Packagist. You may use it or check it's source code, maybe you'll get better idea and can build a better one. But probably there are a lot better ones available on the web as well.

Upvotes: 5

frederickf
frederickf

Reputation: 1531

I think the problem you're trying to solve isn't really specific to PHP and either of the two techniques you've described could be viable ways to handle global configurations.

Having said that, I agree with Rangad, the solution is to use Dependency Injection. At it's simplest this pattern just means passing dependency's to a class/object/function as arguments. For example,

class Thing () {

    private $host = '';

    function __contructor($host) {
        $this->host = $host;
    }

    function getHost() 
    {
        echo $this->host;
    }
}

$thing = new Thing( Config::get('database.host') );
$thing->getHost();

$thing2 = new Thing (Config::get('someOtherDatabase.host') );
$thing2.getHost();

This encapsulates your classes. Now they can be used in tests or even other applications so long as the needed dependences can be provided.

The nice thing about this is that you can use it with either of your proposed config options and probably others. For example if you're looking for something simple there's Pimple, a PHP Dependency Injection container written by the creator of the Symphoy PHP framework that in my opinion is great for smaller PHP projects http://pimple.sensiolabs.org/.

Upvotes: 0

Related Questions