Manipulating Configuration Data with Zend_Config

Out With The Old…

A few months ago, I read about Zend_Config, a Zend Framework component that offers a complete API to read and write configuration data in a variety of formats. This was interesting to me, because one of the most common tasks I encounter, in almost every Web application I work on, involves writing a module to save and retrieve user-defined configuration values. Thus far, I’d been using a hand-rolled library for this task; however, this library was now fairly dated and didn’t take advantage of many of the newer PHP 5.x features and so, I’d been looking for a more modern replacement.

Zend_Config seemed to meet my needs, so I played with it a little and then deployed it in a couple of projects. It did everything I needed it to, and was easy to integrate with both framework and non-framework PHP projects. It also has a couple of neat features, such as the ability to merge multiple configurations together. Keep reading and I’ll give you a quick crash course in how it works.

Busy Signal

Before diving into the code, a few notes and assumptions. I’ll assume throughout this article that you have a working Apache/PHP/MySQL development environment, and that you have downloaded and installed the latest version of the Zend Framework. I’ll also assume that you know the basics of working with classes and objects in PHP.

The Zend_Config component provides an API to read and write configuration files, in array, INI or XML format. Data can be structured in “flat” or “tree” style, and the component provides a consistent API to access data items, regardless of the format in which they are stored.

Let’s begin with a simple example that illustrates Zend_Config in action. Consider the following simple XML configuration file:

Here’s a PHP script that illustrates how to access configuration data from this file:

Zend_Config offers adapters for two different configuration file formats, INI and XML, implemented as Zend_Config_Ini and Zend_Config_Xml respectively. This script uses the Zend_Config_Xml adapter to read the configuration file and convert it into an object representation. It begins by setting up the Zend auto-loader, which takes care of automatically loading Zend Framework components as needed. It then initializes an instance of Zend_Config_Xml, passing it the file name and (optionally) the parent node to start with. Children of the specified parent node can now be accessed using standard object->property notation.

Here’s what the output looks like:

Setting Rules

You can omit the node name, in which case Zend_Config will create an object tree beginning with the document root node. The following revision illustrates this, producing the same output as before:

Node attributes are converted into child properties of the parent node, and node lists can be accessed using indexes. Consider the following configuration file, which illustrates these aspects:

Here’s a PHP script to access these values:

Format Frenzy

If your data is stored in INI format, it’s just as easy to access it. Here’s an example of an INI configuration file:

To read configuration data from an INI file, use the Zend_Config_Ini adapter, as shown below:

On the previous page, I’d said that Zend_Config offers adapters for two file formats, INI or XML. This is not strictly true; apart from these formats, it’s also possible to store configuration data as a PHP array, and read this directly into a Zend_Config object. If your configuration files are unlikely to be modified by hand, storing data as a PHP array is usually a good idea, because it offers one key advantage: a PHP opcode cache like APC can read and cache this data, reducing file reads and improving performance.

Here’s an example of the same configuration data in a PHP array:

And here’s the PHP script you’d use to read it. The key difference here is that the configuration file containing the PHP array is loaded into the script with require_once(), and the array (not the file name) is then directly passed to Zend_Config.

Zend_Config doesn’t yet support YAML, but in case you have configuration data in this format, consider these two approaches, which make use of the syck extension and the spyc library respectively to bring YAML support to Zend_Config.

A Tidy Nest

Zend_Config is also able to read nested configuration data, whether in INI, XML or array format. To illustrate, consider the following XML file:

Here’s an example of accessing a node value:

It’s useful to remember that Zend_Config implements the Iterator interface, which means that you can also loop over a set of configuration values, like this:

Good Parenting

Zend_Config also supports a form of inheritance, wherein sections of a configuration file can “inherit” configuration elements from other sections. When using XML configuration files, this inheritance is indicated with the special keyword “extends”. Here’s an example of an XML configuration file that uses this feature:

As a result of this, keys that are not explicitly set in the child block will inherit values from the parent block. This is clearly seen in the following script:

When using INI files, inheritance can be indicated through the colon symbol, as shown below:

Zend_Config also makes it possible to merge configuration data from more than one file, via its merge() method. Later items with the same name will override earlier ones. Here’s an example:

The Write Stuff

In addition to reading configuration files, Zend_Config also offers the Zend_Config_Writer, which provides an API to write configuration files. Zend_Config_Writer comes with adapters for INI, XML and PHP array formats, making it possible to save configuration data in the format best suited for your application’s needs.

Here’s an example, which writes an INI file:

Every Zend_Config_Writer implementation exposes a write() method, which takes care of writing the configuration file in the correct format. This write() method requires two arguments: the name of the configuration file, and a Zend_Config instance containing the configuration data to be written. The previous example uses the Zend_Config_Writer_Ini implementation, which produces an INI file. The Zend_Config instance required by the write() method is created from a PHP associative array, which holds the configuration data as key-value pairs.

Prefer XML? Simply switch the previous script to use the Zend_Config_Writer_Xml adapter:

If you’d like the output to be stored as a native PHP array, use the Zend_Config_Writer_Array adapter:

Here’s what each of the scripts above would produce:

Building XML Trees

You can also create nested trees of configuration data with Zend_Config_Writer, as illustrated in the next example:

Here’s what the output looks like:

The previous examples all defined an array, used the array to initialize a Zend_Config object, and then wrote the Zend_Config object to a file. A simpler approach is to dynamically build the Zend_Config object by adding parameters to it using object->property notation. Here’s an example, which is equivalent to the previous one:

When nesting INI configuration data, you can define the separator used for the different nesting levels, via the setNestSeparator() method. The default separator is a period.. Here’s a revision of the previous example, which demonstrates:

You can also decide whether configuration values should be divided into sections or not via the setRenderWithoutSections() method, which accepts a Boolean argument. Here’s how you’d use it:

The following image illustrates the difference in output:

Task Manager

Now that you know how Zend_Config works, let’s look at using it in a practical example. Assume for a moment that you’re writing a Web-based task scheduling application, and you’d like some aspects of the application to be user-definable. Your plan is to give your users a browser-based configuration tool to define these values, and then store their selections in a configuration file. The data in this file could then be used by your controllers and models as needed.

Zend_Config has a dual role to play here. On GET requests, it must check if an existing configuration file exists and, if yes, it must pre-populate the form with the current configuration. On POST requests, it must validate the POST-ed form input and write it back to the configuration file.

Since users will interact with the configuration file only through a browser and never edit it directly, it’s quite safe to store the configuration data as a PHP array; this also simplifies integration with the rest of the application and offers some caching possibilities.

Here’s the complete script:

Nothing special here: the script checks if a configuration file exists and if yes, loads it into a Zend_Config object. Within the form, conditional tests are used to check the Zend_Config object data and automatically check/select/populate the various form fields with the correct values. Once the user submits the form, the Zend_Config object is recreated with the new configuration and written back to the file using the Zend_Config_Writer_Array writer.

Here’s what the form looks like:

As these examples will have illustrated, Zend_Config only does one thing – managing configuration data – but it does that thing very well. It not only has the ability to read and write data in INI, XML and native PHP formats, but it also offers built-in support for nested configuration trees and inheritance. In short, if you need manage your application’s configuration data, Zend_Config probably has everything you need (and a bit more besides). Try it out the next time you sit down to write a PHP application, and see for yourself!

Copyright Melonfire, 2010. All rights reserved.