Archive

Posts Tagged ‘Zend_Config’

Zend_Config Benchmark – JSON, Array, INI, XML, YAML

March 6th, 2012 8 comments

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.

 

Categories: PHP, Zend Framework Tags: ,