ZF Config XML vs Ini Showdown

Back at php|tek11 Rob Allen gave a talk on optimizing Zend Framework. During the tutorial he pointed out how you could cache your application config files so that they are not loaded and parsed at every request. This got me thinking about something that had been bugging me for a long time. What is the best format for your config file?

Back before ZF 1.0 there was a fair bit of confusion on how to do everything “right”, especially setting up a “modular” build. One of the first good examples out there was made by Dasprid, and he used an xml based application config. We are talking back in early 2007 when it was the wild west for ZF. Since then, I only see people using ini files.

Well, here it finally is, the official synthetic Zend_Config benchmark shootout.

I created an ini and a xml config file with the same content.

[production]
bootstrap.path="../application/Bootstrap.php"
bootstrap.class="Bootstrap"
routes="../application/config/routes.xml"
phpSettings.display_startup_errors=0
phpSettings.display_errors=0
phpSettings.date.timezone="America/New_York"
autoloadernamespaces[]="Zend"
autoloadernamespaces[]="My_"
resources.frontController.controllerDirectory="../application/controllers"
resources.frontController.moduleDirectory="../application/modules"
resources.frontController.defaultModule="default"
resources.frontController.plugins[]="My_Controller_Plugin_IDS"
resources.frontController.plugins[]="My_Controller_Plugin_Messy"
resources.modules[]=
resources.view.encoding="UTF-8"
resources.view.escape="htmlentities"
resources.layout.layout="default"
resources.layout.layoutPath="../application/layouts"
resources.db.adapter="MySQL"
resources.db.params.username="USER"
resources.db.params.password="CHANGEME"
resources.db.params.dbname="DB"
resources.db.isDefaultTableAdapter=true

xml.xml:

<config>
    <production>
        <bootstrap>
            <path>../application/Bootstrap.php</path>
            <class>Bootstrap</class>
        </bootstrap>
        <routes>../application/config/routes.xml</routes>
        <phpSettings>
            <display_startup_errors>0</display_startup_errors>
            <display_errors>0</display_errors>
            <date>
                <timezone>America/New_York</timezone>
            </date>
        </phpSettings>
        <autoloadernamespaces>
            <Zend>Zend</Zend>
            <S3>My_</S3>
        </autoloadernamespaces>
        <resources>
            <frontController>
                <controllerDirectory>../application/controllers</controllerDirectory>
                <moduleDirectory>../application/modules</moduleDirectory>
                <defaultModule>default</defaultModule>
                <plugins>
                    <ids>My_Controller_Plugin_IDS</ids>
                    <messy>My_Controller_Plugin_Messy</messy>
                </plugins>
            </frontController>
            <modules>
                <placeholder/>
            </modules>
            <view>
                <encoding>UTF-8</encoding>
                <escape>htmlentities</escape>
            </view>
            <layout>
                <layout>default</layout>
                <layoutPath>../application/layouts</layoutPath>
            </layout>
            <db>
                <adapter>MySQL</adapter>
                <params>
                    <username>USER</username>
                    <password>CHANGEME</password>
                    <dbname>DB</dbname>
                </params>
                <isDefaultTableAdapter>true</isDefaultTableAdapter>
            </db>
        </resources>
    </production>
</config>
    

As you can see, xml is a bit more verbose! Then I made a simple script to hammer them.

require_once 'Zend/Config/Xml.php';
require_once 'Zend/Config/Ini.php';

$runs = 10000;

$start = time();
for ($i=0;$i<$runs;$i++){
    $config = new Zend_Config_Xml('xml.xml','production');
    clearstatcache('xml.xml');
}
echo "XML,$runs," .(time()-$start)."\n";

$start = time();
for ($i=0;$i<$runs;$i++){
    $config = new Zend_Config_Ini('ini.ini','production');
    clearstatcache('ini.ini');
}
echo "INI,$runs," .(time()-$start)."\n";

My initial attempts showed xml to be faster but that seemed weird, until I noticed that the file was being cached. Hence the addition of clearstatcache to replicate individual connections. If we run this a bunch of times for different run levels we get the following table (time is in seconds).

Runs XML INI
10000 3 3
100000 36 31
200000 72 60

So we can see, the XML version, at load, does show to be slower than an ini file. Whether this is due to the xml parser, or the simple fact that the ini file is half the size (977b vs 1824b) I do not know. And yes, I know a bunch about micro-optimization and artificial benchmarks. My sites also don’t get a sustained 3k hits/s. What I do know is I am switching over to ini.

Leave a Reply