2

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.

6
  • If you are building a new app, why not get rid of any unnessessary global code and rely on proper depdendency injection(even if that means to manually pass that config object into the function)? Commented Jul 1, 2014 at 17:35
  • 1
    Use a configuration object and use dependency injection to make it available. If you're in a framework of some kind, you probably already have DI solutions. You can always roll your own, like global container, pub/sub, or reflection injection. If you're not in a framework, use a component from another framework rather than writing your own, like Symfony Config Component. Commented Jul 1, 2014 at 17:40
  • Thanks @Rangad for your comment. I'm a newbie OOP developer, so most of my code isn't OO. I'm trying to transform some parts of it in order to take a OO approach. Commented Jul 1, 2014 at 17:57
  • Thanks @bishop for your comment. If I doesn't understand wrong you are recommends method 2 but how do you deal with function's inside calling? Using a Symfony Config Component seems to be to heavy solution for my little application :-P Commented Jul 1, 2014 at 17:59
  • @PacoOrozco: "How do you deal?" Through dependency injection. Your configuration is the dependency and you need to inject it into different places. There are lots of patterns to dependency injection. One such pattern is "store it in globals", but that is a problem for all the reasons you mentioned. Other patterns are available, but increasingly difficult to implement. A good framework will save you all this work. Even though your application seems "little", building up from a framework will simplify this -- and all the other -- problems you're going to face as your app grows. Commented Jul 2, 2014 at 15:18

2 Answers 2

5

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks @werewolf-the-alpha but I want to use a INI file. I think is more user friendly, an easier to generate from PHP.
0

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/.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.