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.
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?
PHP Config Class
I should also add that this doesn’t seem to work with multidimensional arrays — I’m working on this. If anyone has a solution, I’d appreciate it.
1 Answer 1
You can continue to use a class if you want, but I think making a config class is overkill. Just a plain config file with constants should be good enough. It has less overhead and less abstraction. As for loading a specific config file, you can use a helper function to simulate what you have here, or just manually include it. Not everything has to be in a class.
echo Config::get( 'database.host' ); //VS echo DB_HOST; $config->load( 'config' ); //VS config( 'config' );//helper function //OR include 'config/config.php';
I think there’s something wrong with your load() method by the way. You are resetting the array each time you load a new config file. I believe it should look something like so.
static::$items[] = include "config/$filepath.php";
I’m not sure I really agree with setting $items to static. I understand you aren’t instantiating the class, but I think you should, and then just make this a normal property. Typically when I think of static properties, I think of properties that aren’t supposed to change, but you are adding to it, which seems contradictory. Maybe I’m wrong here, but this just seems odd to me. Of course I really just dislike the static keyword altogether.
You can set an array element to a variable and unset it all at the same time by using array_shift() . For example.
$filepath = array_shift( $input );
It might be worth profiling that explode/implode task and comparing it to a substr version. Assuming the array version is faster, then I would suggest changing the first delimiter to something other than a period since that’s the only one you care about. Maybe a forward slash or underscore instead? It would make needing to implode the array unnecessary.
$input = explode( '/', $key); $filepath = array_shift( $input ); $key = strval( $input );
PHP empty() should really only be used when checking arrays. A string can be determined just by querying it. For example:
Finally, I would think that the «default» return value for your getter would be NULL or FALSE. Why return the entire configuration array? This could be confusing, especially since you mentioned using multidimensional arrays. Speaking of which, what about this doesn’t work for them? The config file? The getter? What exactly is happening, and what are you expecting? Besides the things I already mentioned, I don’t see anything that would cause an issue.
Edit to clarify last comment:
Early check and return ensures less overhead and better legibility.
public static function get( $key = null ) < if( ! $key ) < return static::$items; >//etc.
I don’t condone the use of variable-variables, but its the only way I can foresee doing this. Unless you can put all of those arrays into another array, then you can access them as associative arrays.
$input = explode( '.', $key ); $filepath = array_shift( $input ); if( count( $input ) > 1 )
Creating a configuration Class in php
I am creating a system for a client that loads information from an XML file and then parses the information where needed. For this, I have got this class:
/** @return Config */ public static function Init() < return static::$init = ( null === static::$init ? new self() : static::$init ); >public function RequireFiles() < require_once static::$connectionfile; require_once static::$GWPATH . 'libraries/functions/user.loggedin.php'; >public function LoadConfig() < static::$cfg = simplexml_load_file(self::CONFIGFILEPATH); $path = static::$cfg->paths; $database = static::$cfg->database; static::$ABSPATH = (string) $path->abs; static::$GWPATH = (string) $path->gwpath; static::$CONFIGPATH = (string) $path->configpath; static::$configfile = (string) $path->configfile; static::$CONNECTIONPATH = (string) $path->connectionpath; static::$connectionfile = (string) $path->connectionfile; static::$db_hostname = (string) $database->hostname; static::$db_username = (string) $database->username; static::$db_password = (string) $database->password; static::$db_database = (string) $database->name; > public function GetLink() < if (empty(static::$link) || null === static::$link) $this->SetLink(); return static::$link; > public function SetLink() < static::$link = new Database($this->GetDBHostname(), $this->GetDBUsername(), $this->GetDBPassword(), $this->GetDBDatabase()) or die("Failed to connect to the server. Error: " . static::$link->connect_error); > private function GetDBHostname() < return static::$db_hostname; >private function GetDBUsername() < return static::$db_username; >private function GetDBPassword() < return static::$db_password; >private function GetDBDatabase() < return static::$db_database; >public function GetConfigXML($do = false) < if ($do == true) return static::$cfg; return null; >>
This is working for me, but I wanted to know if there is a better way to do this? Info:
This is used in this way:
$config = Config::Init(); $config->LoadConfig(); $config->RequireFiles(); $link = $config->GetLink();