Using PHP classes to store configuration data


In my last projects I’m using something I think is useful and it’s not a common practice in our PHP projects. That’s is the usage of a plain PHP’s class for the application’s configuration. Let me explain it. Normally we use ini file for configuration. PHP has a built-in function for parse ini file. It converts the ini file into a PHP array

; our conf.ini file
DEF_APP = home
DEF_BCK = main
DEF_FCT = index
AUTH_ADAPTER = Nov\Auth\Def

[PG1]
driver = pgsql
dsn = "pgsql:dbname=pg1;host=localhost"
username = nov
password = nov

And now we use our ini file:

$conf = parse_ini_file("conf.ini", true);
print_r($conf);

Another typical configuration file is xml. We also can use built-in functions within PHP when we want to parse xml files. There are also projects that use plain php files, and even yaml files (especially Symfony users)

There are many standard options. Why I prefer a different one then? I like plain PHP classes because the IDE helps me with autocompletion. The usage is quite simple. Instead of using parse_ini_file function we only need to include our configuration class within our project.

class Conf
{
 const DEF_APP = 'index';
 const DEF_BCK = 'Index\Bck\Main\Page';
 const DEF_FCT = 'init';
 const AUTH_ADAPTER = "Nov\Auth\Def";

 const DB_PG1 = 'PG1';
 const DB_PG1_DRIVER   = 'pgsql';
 const DB_PG1_DSN      = 'pgsql:dbname=pg1;host=localhost';
 const DB_PG1_USERNAME = 'nov';
 const DB_PG1_PASSWORD = 'nov';
}

Sometimes I want to use a variable stored into the application’s configuration but I don’t remember exactly the name of the variable. If I’ve got the configuration stored into a PHP array from a ini file (or xml, yaml, … ). I need to open the configuration file and find the name of the variable to use in my code. With a PHP class IDEs like Netbeans of VIM will pop up an autocompletion hint with the name of the variable

An example of coding autocompletion with Netbeans
The same with VIM

And that’s all. Maybe the worse part of this technique is if our application writes the configuration file (a typical installer.php). In this case we need to build the PHP’s class file and it’s slightly more complicated than writing a simple ini file.

What do you think about it? Do you use another different way?

About these ads

About Gonzalo Ayuso

Web Architect specialized in Open Source technologies. PHP, Python, JQuery, Dojo, PostgreSQL, CouchDB and node.js but always learning.

Posted on January 10, 2011, in php, Technology, tips. Bookmark the permalink. 14 Comments.

  1. I think the biggest downsides are not beiing able to do:

    [production]
    ; stuff..

    [development : production]
    ; stuff to override on dev server

    and:
    db.user = foo
    db.pass = baz
    db.name = bar

    /2 cents

  2. Good point. That’s a problem. When I need to face to this issue I use the following tricks:

    First I need different environments (production, development, testing, …) I normally create different configuration classes and I include de class I need depending on a environ variable (normally defined at virtualHost configuration). TDD people doesn’t like this kind of environments selection. If we need some kind of dependency injection we can pass a new instance of the configuration class instead of using it statically

    The other point, if I need a tree in the configuration, I use “_” to separate elements. It’s not perfect but it works. The IDE’s autocompletion is essential for me. I see the configuration class as a key-value database. If need a tree I simulate it with “_” but keeping the key-value.

  3. I just realized that the section inheritance with the
    [foo : bar]
    notation is zend framework specific so ‘overriding’ doesn’t work as in my example, my bad..

    I do however find it important to be able to define different sections. Same goes for ‘tree’ configuration. It allows me to do:

    $db = DB:factory($cfg[‘db’]);

    That way autocompletion becomes a lot less important. But I guess that it ultimately just boils down to personal preference..

  4. I use database tables that allow me to have the group similar to the INI file. Then I load these into variables in the code on start up of the application. The variables are then available for Auto-Complete. Of course, some settings still need to be outside of this to connect to the database. A INI is still used with the most common, non changing values. Reading the INI is still handled by a class similar to the database tables so the code complete is available.

    • Normally I avoid the databases for those kind of things. Database connection is an slow operation (can be a bottle neck). If you assume your application will have at least one DB connection it’s not a problem (you are going to connect to the database sooner or later). But sometimes I don’t use any database (cached queries for example) and I don’t want to use a db connection only for configuration. The good point is obiously the configuration management. With the configuration stored within the database is pretty straightforward to modify and change values. If we use “changing values” in the configuration it’s a good choice

  5. If you use a class why not add methods?

    class Conf{
        const DEV = 0;
        const LIVE = 1;
    
        public static function domain($environment){
            return $environment == self::DEV ? 'dev' : 'www' ;
        }
    
        const DB_TABLE = 0;
        const DB_USER = 1;
        const DB_PASSWORD = 2;
    
        public static function db($environment,$part = null){
            $values = array(
                                   array(
                                         'db_dev',
                                         'user_dev',
                                         'password_dev',
                                   ),
                                   array(
                                         'db',
                                         'user',
                                         'password',
                                   ),
                             );
             
             if($part === null){
                 return $values[$environment];
             }
    
             return $values[$environment][$part]
        }
    }
    

    But i wonder if the convenience of auto-completion should be that important to add code, if you can read from an array which is both human and machine readable.

    It’s not that you are going to place config values everywhere in your code. So having to look from time to time in the config file will not slow you down that much.

    • The first time I’d used a class as configuration file I also used functions inside. The problem is when you start to code business logic within the class, it becomes into one strange spaghetti configuration class (data, code, ifs, …). I prefer to use a simple and plain class with consts and put all funtions outside (maybe in a wrapper). My idea is keep the configuration class “pure” (I know I’m a bit rare ;) ). In fact I had classes very similar than your example

      By the other hand normally I use those kind of configuration classes to store database’s connection data. In my daily work I need to connect to different databases depending on the situation (not only one database for production). That’s means I need to open again and again the configuration file. Because of that autocompletion is essential for me

  6. In all my projects, for configuration I prefer to use Yaml (http://www.yaml.org/).

    Yaml sintax is very clean, and human readable. Any person can change (with care) a yaml config file.

    Autocompletion is not a good reason for me to change to php constants, unless maybe if the configuration data is heavily used in the programming.

    Regards!

  7. For some of our sites, we use a class hierarchy to define our configuration, and (because we are limited to 5.2, therefore no LSB, we can’t define a superclass that contains this behaviour) define a static GetInstance()-like method on the classes.

    So we have a base config class:

    class Config_MyConfig
    {
    	public static function GetInstance()
    	{
    		$className = __CLASS__;
    		$subClassName = $className.ENVIRONMENT_MODE;
    		if (class_exists($subClassName)
    		{
    			return new $subClassName();
    		}
    		else
    		{
    			return new $className();
    		}
    	}
    	
    	/* We define all of our config settings as public properties with appropriate defaults */
    }
    

    and then we extend this class for each of our differing environments, with production being the default (in Config_MyClass base) so that we only need to override settings in our subclasses.

    So we can use the same call to get at our config for any different environment / installation / whatever:

    Config_MyConfig::GetInstance()->CONFIG_PROPERTY

    We use this way of defining configs for things like installation-specific configs also, which we keep in
    the same dev webroot (since all installations run the same codebase)

    Not sure how “good” this solution is, but it works for us.

    • Cool. In fact when I wrote http://wp.me/pqmgV-1U, it was for doing something like this. I’ve been working with code like your example too. It works. The problem is if you want to do TDD. If you want to play with dependency injection this way of work can cause problems but for me is good. ;)

      I prefer to keep plain and “pure” the classes and avoid dependencies as I far as I can. But it’s my only personal opinion.

  8. I forgot to mention (although it’s pretty obvious) but this gives us the advantages of both inheritance and IDE autocomplete.

  9. But 1 more problem with maintaining the constants in class that’s concatenation.

    Check this example.

    define(‘ROOT_PATH’, ‘/project’) ;
    define(‘CLASS_PATH’, ROOT_PATH . ‘/class’) ;

    You cannot do this in class constants because it’s class defination

    class Conf {
    const ROOT_PATH = ‘/project';
    const CLASS_PATH = CLASS_PATH . ‘/class';
    }

    this will give u the error.

  10. What about APC load defines http://sg.php.net/manual/en/function.apc-define-constants.php? Is this good solution?

  11. How can I save back changed values?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 1,003 other followers

%d bloggers like this: