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>&lt;?php

// Setup Zend Framework Autoloader and Bootstrap Application
include '_common.php';

$iterations = 1000;
$config = new Zend_Config($application-&gt;getOptions());

/**
 * Writes
 */

$start = microtime(true);
for ($i = 0; $i &lt; $iterations; $i++) {
	$iniWriter = new Zend_Config_Writer_Ini(array('config' =&gt; $config, 'filename' =&gt; 'data.ini'));
	$iniWriter-&gt;write();
}
echo "INI Write   - $iterations - " . (microtime(true)-$start) . "s\n";

$start = microtime(true);
for ($i = 0; $i &lt; $iterations; $i++) {
	$jsonWriter = new Zend_Config_Writer_Json(array('config' =&gt; $config, 'filename' =&gt; 'data.json'));
	$jsonWriter-&gt;write();
}
echo "JSON Write  - $iterations - " . (microtime(true)-$start) . "s\n";

$start = microtime(true);
for ($i = 0; $i &lt; $iterations; $i++) {
	$xmlWriter = new Zend_Config_Writer_Xml(array('config' =&gt; $config, 'filename' =&gt; 'data.xml'));
	$xmlWriter-&gt;write();
}
echo "XML Write   - $iterations - " . (microtime(true)-$start) . "s\n";

$start = microtime(true);
for ($i = 0; $i &lt; $iterations; $i++) {
	$yamlWriter = new Zend_Config_Writer_Yaml(array('config' =&gt; $config, 'filename' =&gt; 'data.yaml'));
	$yamlWriter-&gt;write();
}
echo "YAML Write  - $iterations - " . (microtime(true)-$start) . "s\n";

$start = microtime(true);
for ($i = 0; $i &lt; $iterations; $i++) {
	$arrayWriter = new Zend_Config_Writer_Array(array('config' =&gt; $config, 'filename' =&gt; 'data.array'));
	$arrayWriter-&gt;write();
}
echo "Array Write - $iterations - " . (microtime(true)-$start) . "s\n";

/**
 * Reads
 */

$start = microtime(true);
for ($i = 0; $i &lt; $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 &lt; $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 &lt; $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 &lt; $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 &lt; $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 &lt; $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.

 

10 thoughts on “Zend_Config Benchmark – JSON, Array, INI, XML, YAML

  1. I guess by “human writable” you mean non-developer humans. JSON and PHP array notation are both pretty human read/writeable.

  2. Could you add this one ?
    Like:
    $config = new Zend_Config(require ‘config.php’);
    with config.php:

    It may be the fastest

  3. 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)

  4. The gold supply is used as a rosland capital proxy for gold.
    This investment product is one of the most popular
    choices. The advantage in buying numismatic over bullion
    lies in where to store it, they can purchase GLD and
    add the yellow metal, the International Monetary Fund is expected to grow even higher.
    Gold bullion, on the other hand, is the most readily
    available form of gold bars or coins.

  5. An impressive share! I have just forwarded this onto a co-worker who
    was conducting a little research on this. And he in fact bought
    me lunch due to the fact that I found it for him…
    lol. So allow me to reword this…. Thanks for the meal!!
    But yeah, thanks for spending some time to talk about this matter here on your web page.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>