radiergummi / libconfig
Configuration object creation for PHP apps
Requires
- php: >=5.3.0
This package is auto-updated.
Last update: 2024-10-29 03:45:45 UTC
README
Simple php class to create a key-value storage.
Basically, you can just throw your configuration at it, be it arrays, json, files or even directories, and libconfig will make it accessible in an intuitive way. You can get
, set
and add
it, count it, iterate over it or access it as an array. Each method has its tricks up its sleeve. More on that below.
Note: I also made a singleton version of this which is available here.
Why? Because using stuff likeConfig::get('key')
from anywhere without an instance is pretty darn comfortable.
Installation
###Installation via Composer (Packagist):
-
Include the following in your composer.json file:
"require": { ... "radiergummi\libconfig": "~1.0" }
-
Then, run
php composer.phar install
###Installation via source:
- Download from Github
- Drop the src/libconfig folder into your codebase at
vendor/Radiergummi
(you don't need the parent folders) - Use a PSR-4 Autoloader to include it!
Usage
Creating a Config object
Create a config object like this:
$config = new Config($data);
where $data
can be an array or a json string, a file or folder path.
Creating a Config object with a file as a parameter
To directly include a json file, use
$config = new Config(PATH . 'example.json');
The only requirement is the complete path to be valid.
I often use php files like the one below to store configuration. So you could also use
$config = new Config(PATH . 'example.php');
PHP Config file:
<? return array( 'foo' => 'bar' );
Creating a Config object with a folder as a parameter
To parse a folder containing your configuration files, use
$config = new Config(PATH . 'app/config');
The only requirement is the complete path to be valid.
A note on INI files: Honestly, why would you want to use those for configuration when you have php and json at hand? Maybe when I get a good idea on how to implement that in an elegant way.
Advice on implementation
Incorporate this into your project: Set the namespace to that of your app and keep it in the app system directory. That way, you can access the config the most hassle-free way.
Catch possible exceptions: Libconfig will throw a RuntimeException immediately if data cannot be read. If you know something could go wrong, set up try-catch blocks.
Don't hardcode: Use config files whenever possible - for files, routes, i18n, paths and classlists, ... .
Be reasonable: There comes a point where redis or a real DB might make more sense. Reevaluate from time to time.
Hack the code however you like: You are free to use this library in any project, commercial or not (see the license). However, it would be nice of you to drop a curious fella a note what you used my work for and what you changed :).
Methods
set
inserts a value into a key:
$config->set('foo', 'bar');
That will add the following to the config array:
Array
(
[foo] => bar
)
To set nested config values, you can use dots to seperate keys:
$config->set('font.roboto.italic.regular', 'roboto-regular-italic.woff');
That will add the following to the config array:
Array
(
[font] => Array
(
[roboto] => Array
(
[italic] => Array
(
[regular] => roboto-regular-italic.woff
)
)
)
)
get
returns the value for a given key:
$config->get('foo'); // bar
To access nested config values, you can use dots to seperate keys:
$fontlist = $config->get('font.roboto.italic'); // Array $fontfile = $config->get('font.roboto.italic.regular'); // roboto-regular-italic.woff
You can optionally specify a fallback value in case the desired key is not present:
$config->get('app.server.port', '8080');
To retrieve the whole configuration, just call get without arguments:
$config->get();
has
checks wether a setting exists or not
$config->has('foo.sub.key'); // true
erase
removes a key from the settings
$config->erase('foo.sub.key');
add
Adds another array to the configuration. The data is merged, which means that keys with the same name will overwrite previously existing ones. Maybe a possibility to insert them with changed names should be implemented here?
$config->add(file_get_contents('another.json'));
Magic methods
__tostring
returns the complete data array:
print_r($config); // Array
(Note: This is redundant. You can either call $config->get()
or just $config
, same effect. I find it to be not very self-documenting, but who am I to tell you how to code.)
Implemented Interfaces
Array access
You can also access and edit all data as an array:
$port = $config['app']['server']['port']; // 8080
Countable
The Config object can be counted:
$settings = count($config);
Iterator
You are able to iterate over the Config object:
array_walk_recursive($config, function ($value, $key) {
echo "$key holds $value\n";
});
Some thoughts on Exceptions
I have only implemented RuntimeException
as the exception type throughout libconfig. Why? Possible things that can go wrong are files not being found or data not being parsable. In either case, you've got a problem you should catch:
try { $config->add('inexistent/path/to/file.json'); } catch (Exception $e) { $app->shutdown(502); if (ENV === 'dev') throw new \MyApp\Exceptions\FileNotFoundException($e); }
That way, exception handling is bound to your app and you don't have a few more arbitrary exception types to deal with.
TODO
Bugs
- Counting the object recursively has no effect currently, and I don't know why.
Sometimes while parsing JSON, a JSON_LAST_ERROR 1 is thrown, meaning the maximum depth is reached, even if handling JSON with no nesting at all. There must be some recursion going on.(Fixed)
Improvements
- Parts of the code are a bit messy right now, especially the
add
-method. - I would like to modularize the internals a bit - parsing input should be done via drivers or at least inside of specialized methods for each content type. (In progress)
libconfig should be unit tested(Done)
Features
- INI Support (but just to stay competitive) (In progress)
- ?
How to contribute
I would love to see other people contribute their ideas to this project. However to ease the process, please keep the following in mind:
- If you find a bug, please create an issue for it, tag the issue with bug and include the code to reproduce it.
- If you want to request or discuss a feature, please create an issue for it, tag it with enhancement and discribe it as detailed as possible.
- If you want to contribute actual code, please fork the repository, create a new branch in your fork (eg. feature-ini-support), make your changes in it, and create a pull request.
Thank you!