Zend_Config Benchmark – JSON, Array, INI, XML, YAML
Zend Framework supports reading and writing from configuration files of 5 different types (JSON, Serialized Array, INI, XML, and YAML).
It is most common to see INI used for application config files. But config files can be used for many different uses including navigation, translations, or ACLs.
If you application relies on parsing one or several config files each time it is bootstrapped it is important that you select a file format that is fast to parse. But you also want to select a config file format that is easy for a human to read and edit.
In a recent application I am building I also had the need to write modifications to config files, so I also benchmarked the Zend_Config_Writer components.
First I started with a relatively small config INI config file and parsed this to a Zend_Config object. I used this Zend_Config object for benchmarking the writers. Then I used the writen config files for benchmarking the readers.
Following is the source config file:
<pre>includePaths.library = APPLICATION_PATH "/../library" appnamespace = "Application" autoloaderNamespaces[] = Bar_ autoloaderNamespaces[] = Foo_ ; PHP Settings phpSettings.display_startup_errors = 0 phpSettings.display_errors = 0 phpSettings.error_reporting = 2147483647 phpSettings.log_errors = 1 phpSettings.error_log = APPLICATION_PATH "/../data/logs/phperrors.log" ; Bootstrap bootstrap.path = APPLICATION_PATH "/Bootstrap.php" bootstrap.class = "Bootstrap" ; Locale resources.locale.default = "en_US" resources.locale.force = true ; Front Controller resources.frontController.controllerDirectory.default = APPLICATION_PATH "/controllers" resources.frontController.actionHelperPaths.Bar_Controller_Action_Helper = "Bar/Controller/Action/Helper" resources.frontController.actionHelperPaths.Foo_Controller_Action_Helper = "Foo/Controller/Action/Helper" ; View resources.view.encoding = "UTF-8" resources.view.doctype = XHTML1_TRANSITIONAL resources.view.helperPath.Bar_View_Helper_ = "Bar/View/Helper/" resources.view.helperPath.Foo_View_Helper_ = "Foo/View/Helper/" resources.view.strictVars = on ; Layout resources.layout.layoutPath = APPLICATION_PATH "/layouts/scripts/" ; Mail resources.mail.transport.type = smtp resources.mail.transport.host = "localhost" resources.mail.defaultFrom.email = no-reply@example.com resources.mail.defaultFrom.name = "Example" resources.mail.defaultReplyTo.email = no-reply@example.com resources.mail.defaultReplyTo.name = "Example" ; Application Log resources.log.stream.writerName = "Stream" resources.log.stream.writerParams.stream = APPLICATION_PATH "/../data/logs/application.log" resources.log.stream.writerParams.mode = "a" resources.log.firebug.writerName = "Firebug" resources.db.adapter = "pdo_mysql" resources.db.params.host = resources.db.params.username = resources.db.params.password = resources.db.params.dbname = resources.db.params.profiler.enabled = true resources.db.params.profiler.class = "Zend_Db_Profiler_Firebug"</pre>
Following is the script for running the benchmark. Thanks to Gregory Drake Wilson for getting me started on this benchmark script.
<pre><?php
// Setup Zend Framework Autoloader and Bootstrap Application
include '_common.php';
$iterations = 1000;
$config = new Zend_Config($application->getOptions());
/**
* Writes
*/
$start = microtime(true);
for ($i = 0; $i < $iterations; $i++) {
$iniWriter = new Zend_Config_Writer_Ini(array('config' => $config, 'filename' => 'data.ini'));
$iniWriter->write();
}
echo "INI Write - $iterations - " . (microtime(true)-$start) . "s\n";
$start = microtime(true);
for ($i = 0; $i < $iterations; $i++) {
$jsonWriter = new Zend_Config_Writer_Json(array('config' => $config, 'filename' => 'data.json'));
$jsonWriter->write();
}
echo "JSON Write - $iterations - " . (microtime(true)-$start) . "s\n";
$start = microtime(true);
for ($i = 0; $i < $iterations; $i++) {
$xmlWriter = new Zend_Config_Writer_Xml(array('config' => $config, 'filename' => 'data.xml'));
$xmlWriter->write();
}
echo "XML Write - $iterations - " . (microtime(true)-$start) . "s\n";
$start = microtime(true);
for ($i = 0; $i < $iterations; $i++) {
$yamlWriter = new Zend_Config_Writer_Yaml(array('config' => $config, 'filename' => 'data.yaml'));
$yamlWriter->write();
}
echo "YAML Write - $iterations - " . (microtime(true)-$start) . "s\n";
$start = microtime(true);
for ($i = 0; $i < $iterations; $i++) {
$arrayWriter = new Zend_Config_Writer_Array(array('config' => $config, 'filename' => 'data.array'));
$arrayWriter->write();
}
echo "Array Write - $iterations - " . (microtime(true)-$start) . "s\n";
/**
* Reads
*/
$start = microtime(true);
for ($i = 0; $i < $iterations; $i++) {
$configData = new Zend_Config_Ini('data.ini');
clearstatcache('data.ini');
}
echo "Ini Read - $iterations - " . (microtime(true)-$start) . "s\n";
$start = microtime(true);
for ($i = 0; $i < $iterations; $i++) {
$configData = new Zend_Config(include 'data.array');
clearstatcache('data.array');
}
echo "Array to Zend_Config Read - $iterations - " . (microtime(true)-$start) . "s\n";
$start = microtime(true);
for ($i = 0; $i < $iterations; $i++) {
$configData = include 'data.array';
clearstatcache('data.array');
}
echo "Array to Array Read - $iterations - " . (microtime(true)-$start) . "s\n";
$start = microtime(true);
for ($i = 0; $i < $iterations; $i++) {
$configData = new Zend_Config_Json('data.json');
clearstatcache('data.json');
}
echo "JSON Read - $iterations - " . (microtime(true)-$start) . "s\n";
$start = microtime(true);
for ($i = 0; $i < $iterations; $i++) {
$configData = new Zend_Config_Xml('data.xml');
clearstatcache('data.xml');
}
echo "XML Read - $iterations - " . (microtime(true)-$start) . "s\n";
$start = microtime(true);
for ($i = 0; $i < $iterations; $i++) {
$configData = new Zend_Config_Yaml('data.yaml');
clearstatcache('data.yaml');
}
echo "YAML Read - $iterations - " . (microtime(true)-$start) . "s\n";</pre>
Server Details:
- Debian Linux 6.0
- PHP 5.3.9
- json support enabled
- 4 cores
- 8GB RAM
My findings:
| Test | Runs | Time (s) | Runs/s |
|---|---|---|---|
| INI Write | 1000 | 3.94 | 254 |
| JSON Write | 1000 | 1.28 | 781 |
| XML Write | 1000 | 3.17 | 315 |
| YAML Write | 1000 | 1.97 | 508 |
| Array Write | 1000 | 1.56 | 641 |
| INI Read | 1000 | 2.70 | 370 |
| Array Read | 1000 | 0.53 | 1887 |
| Array to Zend_Config Read | 1000 | 1.14 | 877 |
| JSON Read | 1000 | 9.82 | 102 |
| XML Read | 1000 | 3.06 | 327 |
| YAML Read | 1000 | 261.29 | 4 |
My initial reactions was, what the hell is wrong with YAML reading. I read through the source of Zend_Config_Yaml and saw up to 3 calls to preg_replace() for each line of YAML, which doesn’t necessarily indicate that it is flawed. As a follow-up to this post I intend to figure out exactly where the Yaml parser is getting held up. Until I am able to do this, I have discounted YAML entirely.
Of the two formats that are human readable/editable (INI and XML), XML is 20% faster to write and INI is 12.5% faster to read.
Of the non-human-editable formats (Array and JSON), Array wins hands down for reading and is 134% faster than it’s closest contender (INI), but JSON is the fastest for writing (20% faster than Array). The reason Array is so much faster for reading is that the process is entirely native to PHP (you just have include the file and assign it’s response to a variable). Because of this, there is no Zend_Config_Array for reading.
Update:
Thanks to @Balbuzar I noticed that my initial test of unserializing the Array did not return a Zend_Config object (but rather just an array), so I’ve added “Array to Zend_Config Read” above and it is still the fastest of all of the Zend_Config read options, and is 57% faster than INI reading.
Conclusions:
If you need a human-editable config format that is primarily for reads, then INI is your best bet.
If you need speed and can sacrifice human-readability, then Array is the clear winner.
I guess by “human writable” you mean non-developer humans. JSON and PHP array notation are both pretty human read/writeable.
Could you add this one ?
Like:
$config = new Zend_Config(require ‘config.php’);
with config.php:
It may be the fastest
@Balbuzar
Thanks, I have updated the benchmark to include the serialized array version returning a Zend_Config object.
@Errol Sayre
Something deep inside me still says that JSON should never be hand-written.
Hi, try to set ignoreConstants to true and post new results ;)
P.S. Require ‘config.php’ with “return array()” – always faster than any object with method toArray() (called every time when some package works with Zend_Config)
Glad I could help get you started on the benchmarks from http://drakos7.net/2012/02/zf-config-xml-vs-ini-showdown
Other countries censor content and not just rogue regimes such as the Iranian mullocracy. Poor people! http://www.baidu.com