PHP, Meet YAML

  • Posted by Mike Naberezny in PHP

    Just about every PHP application needs some kind of configuration, if only to define the connection to a database. One popular way to store configuration is to use a PHP file itself because it’s convenient and fast for PHP to read. This approach is taken by the Solar PHP Framework and many others.

    However, while PHP is convenient for us as developers, it’s often inconvenient for others. For example, we often leave the task of deploying and configuring our applications with system administrators. For those sysadmins without PHP knowledge, it’s easy to become frustrated by a missing quote, parenthesis, or semicolon in a PHP file.

    Introducing YAML

    Besides PHP itself, the most popular config file formats for PHP applications are INI and XML files. More people understand these formats, but these have problems of their own. The INI format is easy-to-use but not great at representing hierarchical data. XML improves on hierarchical data but is not nearly as easy-to-use as INI.

    YAML is a relatively new format that has been pioneered by the Ruby and Rails communities. It blends the best aspects of XML and INI, giving us a format with the flexibility of XML and the ease-of-use of INI.

    Here’s what a snippet of YAML looks like:

    development:
      adapter:  mysql
      socket:   /tmp/mysql.sock
      encoding: utf8
      database: newsletter_development
      username: the-username
      password: the-password
    

    The YAML site has a more complex example showing what’s possible.

    All Rails applications use the same config/database.yml file to configure the database connection. The snippet above was taken from Chapter 1 in the book, where we developed a simple newsletter application using Rails.

    Let’s explore Ruby’s built-in YAML support and then look at it from a PHP perspective.

    Ruby’s YAML Support

    One of the strengths of Rails is that it is built on a foundation of solid Ruby tools. Rails got the ability to read YAML files for free because YAML support is bundled with Ruby. Fire up IRB and try it yourself:

    irb> require "yaml"
    => true
    irb> h = YAML.load("foo: bar\nbaz: qux")
    => {"foo"=>"bar", "baz"=>"qux"}
    irb> h["foo"]
    => "bar"
    

    Above, we put a YAML document into a string. The YAML.load method then parses it into a Ruby hash, which is simple to use.

    If you have a Rails application handy, such as the newsletter or user group apps from the book, change to the application’s base directory and try this from IRB:

    irb> require "yaml"
    => true
    irb> h = YAML.load_file("config/database.yml")
    => {"development"=>{"adapter"=>"mysql", "encoding"=>"utf8" ... }
    irb> h['development']['database']
    => "newsletter_development"
    

    You can see it’s relatively painless for Rails to read the config/database.yml file just with the YAML support included with Ruby.

    PHP and YAML

    PHP 5 includes built-in support for reading many different formats including INI, XML, and JSON. Unfortunately, YAML support is not yet bundled with PHP like it is with Ruby.

    A few different solutions have appeared to fill this gap. One is pecl/syck, a fast PHP extension that provides bindings to the Syck library written in C.

    Perhaps the best at this time is Horde/Yaml. This library is PHP 5 E_STRICT complaint, uses the familiar PEAR coding standards, and is based on Spyc. Horde/Yaml includes a number of bug fixes, cleanup, and will transparently use pecl/syck if it is available.

    Now, we’ll do the same exercises from above but with PHP and Horde/Yaml.

    Installing Horde/Yaml

    The Horde/Yaml library is distributed as a PEAR package, the analog of RubyGems.

    To install it, run these commands from your shell. If you’re on a Unix-like machine, you will probably have to add sudo before these commands.

    shell> pear channel-discover pear.horde.org
    shell> pear install horde/yaml
    

    If installation is successful, you should see install ok.

    Using Horde/Yaml

    Horde/Yaml, like many newer PHP 5 libraries, does not explicitly use require to load its files. Instead, it uses autoloading. If you’re unfamiliar with this or don’t yet have an autoloader set up, adding something like this to the top of your script will get it working:

    function sample_autoloader($class) {
        require str_replace('_', '/', $class) . '.php';
    }
    spl_autoload_register('sample_autoloader');
    

    With that out of the way, Horde/Yaml is ready to go.

    Let’s look at the equivalent of the first Ruby example, where a string containing YAML is loaded into a PHP associative array:

    $a = Horde_Yaml::load("foo: bar\nbaz: qux");
    
    var_export($a);
    

    The Horde_Yaml::load() method parses YAML into a variable, just like its Ruby counterpart. The output of var_export() is:

    array (
      'foo' => 'bar',
      'baz' => 'qux',
    )
    

    Horde/Yaml can also read from a file with loadFile() or an open stream with loadStream().

    That’s all you need to start reading YAML in PHP.

    Notes

    Be careful in your PHP applications that sensitive YAML files are not web-accessible. Keep them outside of the document root or use an .htaccess file if that’s not an option. If you don’t, your web server will give them to anyone who requests.

    This article focuses on reading YAML, but both Horde/Yaml and Ruby’s built-in YAML support can dump data structures into YAML. Just pass a hash (associative array) to the dump() method of either to get the equivalent YAML string.