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

March 6th, 2012 7 comments

Zend Framework supports reading and writing from configuration files of 5 different types (JSON, Serialized Array, INI, XML, and YAML).

approval payday loans

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: ,

PHP Session Locks – How to Prevent Blocking Requests

December 17th, 2010 33 comments

Many people are aware that modern browsers limit the number of concurrent connections to a specific domain to between 4 or 6. This means that if your web page loads dozens of asset files (js, images, css) from the same domain they will be queued up to not exceed this limit. This same problem can happen, but even worse, when your page needs to make several requests to PHP scripts that use sessions.

Read more…

Categories: PHP Tags: , , ,

Google Wave-style scroll bar jQuery plugin

November 2nd, 2010 9 comments

Google Wave introduced a revolutionary new way of online communication and collaboration. It seemed to swiftly solve the problems inherent our current 40-year-old email system. Unfortunately, it never actually caught on.

Google Wave Scrollbar screenshotIn addition to rethinking email, though, Google Wave’s user interface also rethought things such as scroll bars. I was particularly impressed with Google Wave’s scrollbars which were small, unintrusive, and easy to use.

In it’s tiny form-factor, the Google Wave scroll bar is able to:

  • Indicate document height
  • Indicate current scroll location
  • Scroll by clicking the arrows (dragger doesn’t move until you move your mouse away)
  • Scroll by dragging

After being announced that Google Wave will be retired, I wanted to immortalize this new way of scrolling in a jQuery plugin that does the same thing.

Demo

It currently does not work in IE because it uses CSS image data instead of referencing an actual image URL, but upon changing the image CSS, it will work in IE.

This is an alpha release, so please recommend changes or express your interest in a more configurable plugin.

Categories: Javascript Tags: ,

How to Create Javascript Objects

August 21st, 2009 6 comments

It is easy to create Javascript objects, but this method goes one step further by allowing you to create a Javascript object with private and public methods, as well as private variables. It’s a perfect way to create a single access point for Javascript and Flash to communicate.
Read more…

Sierra Bravo’s Overnight Website Challenge

December 16th, 2008 No comments

Sierra Bravo, a web development shop out of Bloomington, MN is hosting the 2nd Annual Overnight Website Challenge. It is a volunteer event where talented web programmers and designers from the Twin Cities area work side-by-side with deserving non-profit organizations to create a new website for the organization. All in 24 hours.

Read more…

Categories: Events Tags: , ,