• Horde/Yaml 1.0 Released Jan 8, 2008

    Posted by Mike Naberezny in PHP

    Horde/Yaml is a PHP 5 library for easily working with YAML data. This is the package’s first stable release.

    Chuck Hagenbuch started the library as an adaptation of Spyc around six months ago. Since then, he and I have been quietly using and improving it. Along the way, we fixed many issues, added support for pecl/syck, and wrote a test suite with PHPUnit.

    There are a couple of other libraries also derived from Spyc, notably the sfYaml class from the Symfony framework. Since these efforts also found and corrected issues, we incorporated as many of these fixes as we could find and added them to the test suite as we went along.

    At work, we frequently use YAML files for configuring our custom applications because our clients tend to like the format more than the alternatives. We’ve been using Horde/Yaml successfully for quite some time so we think it should generally work well for you also.

    There’s a nice tutorial on working with YAML in PHP 5 over on the new Rails for PHP Developers website. It includes everything you need to get started with Horde/Yaml.

  • PHP, Meet YAML Jan 8, 2008

    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.

  • Zend/PHP Conference 2007 Sep 23, 2007

    Posted by Mike Naberezny in PHP

    I will be presenting again this year at the Zend/PHP Conference, together with Sebastian Bergmann and Matthew Weier-O’Phinney.

    PHP development by teams of developers introduces challenges beyond the mere coding of great algorithms. Agreements are needed about tools, specifications, architecture, design patterns, coding standards, testing, documentation, source code control, staging and deployment. This tutorial session aims to introduce developers to a set of best practices that will help them deliver applications fast and move them to deployment with confidence.

    We will present our full-day tutorial session, “PHP Development Best Practices”, on October 8th. I really enjoyed last year’s ZendCon and I look forward to this one.

  • New in Horde: Routes Sep 15, 2007

    Posted by Mike Naberezny in PHP,Python

    I’m pleased to announce the first release of Horde/Routes, a new URL mapping system for PHP 5. This package provides classes for mapping URLs into the controllers and actions of an MVC system, inspired by Ruby on Rails.

    There are already quite a few existing libraries that do this sort of thing for PHP. Horde/Routes is a compelling alternative.

    I examined most of these PHP solutions and found them all inadequate for various reasons, particularly because we wanted RESTful routing, named routes, sophisticated matching, PHP 5 E_STRICT, and extensive test coverage.

    Since I do quite a bit of Ruby and Python programming, I surveyed the options in those languages and decided to do a full port of the Python library, Routes.

    Horde/Routes provides these features and more:

    • Supports route recognition and generation
    • Sophisticated matching conditions like subdomains
    • Named routes and RESTful route generation
    • PEAR-style naming and coding standards
    • PHP 5 E_STRICT compliant, web framework agnostic
    • A comprehensive unit test suite

    I decided to contribute the code to Horde’s Rampage project because Horde is one of PHP’s oldest and most successful projects. I’m using and contributing to other Horde libraries and I think Rampage is worth your attention.

    The Python version has been around for some time and is very popular with different Python web frameworks. Horde/Routes is now part of that ecosystem now and has already resulted in patches being committed back to the Python version.

    I’ve already used Horde_Routes on several applications. While Horde/Routes is relatively new, it is very feature-rich and well-tested.

    Currently, Horde/Routes is a beta release. Over the coming weeks, we’ll be making some minor changes to the API and adding more documentation, and then it will quickly move to stable.

    Update: The project now has its own pages on the Horde website and was featured on Chuck Hagenbuch’s blog.

  • Better PHPUnit Group Annotations Sep 4, 2007

    Posted by Mike Naberezny in PHP,Testing

    Last week, Sebastian Bergmann wrote about the new support for TestNG-style grouping of tests in the upcoming PHPUnit 3.2. This feature allows individual test methods to be grouped with an @group annotation.

    I typically organize my test case classes into high-level groups such as unit and functional. Method-level group annotations are inconvenient for us because we’d need to annotate every method of every test case class.

    I was discussing this with Sebastian and not long after he had committed changesets 1293 and 1294 to the PHPUnit repository.

    Now, @group annotations on the class inherit to all the methods of that class. When all the test methods of a class belong to the same group, just annotate the class:

    /**
     * @group functional
     */
    class FooTest extends PHPUnit_Framework_TestCase {
    ...
    

    With that one annotation to the class, a command like this one will run all the tests in the class above and any other tests annotated with @group functional:

    $ phpunit --group functional AllTests.php
    

    That’s a great shortcut. It shouldn’t take long to put @group annotations on the test case classes of a project.

    Having the ability to annotate individual test methods is still very useful because test methods (and even classes) may belong to multiple groups.

    Sebastian pointed out a great use case for this in the form of testing bugs that span multiple test case classes. I was already commenting my tests with bug tracker numbers, now I’ve just converted them to @group annotations.

    Whenever we receive a bug report from a client, we will create tests to reproduce the bug and then fix the implementation so the tests pass. This ensures that the bug can be reproduced and that we won’t repeat the same mistake again later.

    Now, the test methods associated with a bug can be annotated like @group bug42. Running phpunit --group bug42 AllTests.php will run only the tests associated with bug #42, regardless of what files and groups those test methods span.

    PHPUnit 3.2 is looking great.

  • Faster TDD with Stakeout.rb Sep 4, 2007

    Posted by Mike Naberezny in PHP,Ruby,Testing

    I’m a big fan of Autotest and it runs almost constantly on my machine. Autotest automatically reruns your tests whenever your files change. Instead of constantly flipping to another shell to rerun your tests, just let Autotest cheerfully do it for you in the background. It’s highly addictive.

    The only problem with Autotest is that it is specific to Ruby. I do a mix of different kinds of programming including Ruby, PHP, Python, and C. I’d like my TDD to be accelerated for all of these languages.

    Thanks to Geoffrey Grossenbach, last week I came across stakeout.rb from Mike Clark. This is a tiny, dead simple Ruby script that runs an arbitrary command when certain files change. This is a stripped-down Autotest for everybody else. I’m sure it has all kinds of other uses as well.

    To get started testing with stakeout.rb, you’ll need Ruby installed. Any recent version is fine and you might already have it installed. Next, grab the stakeout.rb script and add the shebang line to the top (Unix-like OS assumed):

    #!/usr/bin/env ruby -w
    
    if ARGV.size < 2
      puts "Usage: stakeout.rb  [files to watch]+"
    ...
    

    Make the file executable and put it somewhere in your PATH. You can test it out by typing stakeout.rb from an arbitrary directory and you should see the help message.

    Next, change over to a project directory where you have some test files. Most of the projects that I am involved with tend to use some directory structure similar to this:

    /project_name
      /lib
      /test
      ...
    

    To test such a project, run stakeout.rb from the /project_name directory. Most PHP projects using PHPUnit tend to have an AllTests.php file or equivalent to run all the tests, so we’ll assume this for the example:

    project_name$ stakeout.rb "php test/AllTests.php" **/*
    

    The first argument is what command to run when the tests change. The second argument, and any subsequent arguments, are the files to watch for changes. These can use a Ruby globbing pattern. The pattern **/* will watch all files under project_name recursively, which includes lib/ and test/.

    Once stakeout.rb is run, it will show no output but will sit and wait for changes. As soon as you change a watched file, stakeout.rb will automatically rerun you tests and will continue to do so until you exit with Control-C.

  • Wrapping PHP Functions for Testability Aug 1, 2007

    Posted by Mike Naberezny in PHP,Testing

    One of the problems that hampers the testability of PHP code is the coupling created by accessing all of the PHP global functions. This happens often because a large number of useful extensions are accessed only through global functions. Consider the following code snippet:

    $res = ldap_connect($host, $port);
    if (! $res) {
      // error logging
      return false;
    }
    

    There are two code paths shown above: the connection succeeding, and it failing. Both of them are very difficult to test because of the coupling to the global function ldap_connect() provided by the LDAP extension.

    To make it succeed, you’d need an LDAP server. Causing it to fail is easier but it could take a very long time until the connection timeout occurs. Also, the code can’t be tested at all without the LDAP extension. All of these problems are unacceptable.

    The solution is to use to the extension through an object instead of calling the extension function directly. This way, we can inject either the extension wrapper or a mock object for testing.

    However, writing these wrappers and maintaining them can be a pain and this is often the rationale given for not using them. There’s an easy answer to this excuse:

    class ExtensionProxy {
      protected $ext;
    
      public function __construct($ext) {
        $this->ext = $ext;
      }
    
      public function __call($method, $args) {
        return call_user_func_array("{$this->ext}_{$method}", $args);
      }
    }
    

    Since most PHP extensions prefix all of their functions with the name followed by an underscore, it’s easy to wrap them with something like the class above.

    There’s some performance penalty from call_user_func_array() in the above example but you can always write out a class later if that ever actually becomes a problem. Meanwhile, it can get you going very going quickly.

    Our connection example then simply becomes:

    $ldap = new ExtensionProxy('ldap');
    
    ...
    
    $res = $ldap->connect($host, $port);
    if (! $res) {
      // error logging
      return false;
    }
    

    The difference in usage is trivial but this version is easily testable. It now depends only on an $ldap instance, which the class needing LDAP can receive in its constructor. To test, now just pass a mock object for $ldap.

    The technique of putting lightweight wrappers around PHP extension functions has been around for a long time. For example, Horde has a small wrapper around the IMAP extension for testing.

    The continued improvements in PHP 5 allow for simple tricks like the ExtensionProxy above, and advances in tools like PHPUnit are making tests increasingly convenient and practical.

    Whatever methods you choose, there really is no excuse for untested (or untestable) PHP code these days. I consider anything without good tests to be broken and you should also.

  • Easier XML-RPC for PHP 5 Feb 19, 2007

    Posted by Mike Naberezny in PHP

    A few weeks ago, I rewrote the Zend XML-RPC client. After fixing some bugs and writing a test suite, I made some enhancements and usability improvements. You can learn more about the new XML-RPC client from its documentation. Here it is in a nutshell:

    Calling Remote Methods

    The new XML-RPC client has always functioned similarly to many existing PHP implementations, providing a call() method:

    $c = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');
    echo $c->call('test.sayHello');
    

    The call() instance method accepts an optional parameter with an array of parameters to marshal to the remote method. These may be native PHP types or PHP objects representing XML-RPC types. The latter is useful for the XML-RPC datatypes that do not map directly to PHP equivalents, such as base64.

    Server Proxy Objects

    The above usage works fine for many purposes but could read easier and gets tedious after many method calls. One of the few advantages of serializing method calls with a protocol like XML-RPC or SOAP is that with a little extra work in the client libraries, the remote service can be exposed in a way that’s very close to a native PHP object. This is where the server proxy comes in.

    In the above example of test.sayHello(), the remote sayHello() method is in the XML-RPC pseudo-namespace test. We can use the new XML-RPC client’s getProxy() method to get a proxy to this remote namespace and then use it similarly to a normal PHP object.

    $c = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');
    
    $test = $c->getProxy('test');
    echo $test->sayHello();
    

    Namespaces may be nested to any depth so the XML-RPC method foo.bar.baz() becomes $foo->bar->baz().

    Faults

    Faults resulting from the remote method call are automatically thrown as PHP exceptions. XML-RPC fault responses are thrown as Zend_XmlRpc_FaultException and transport errors are thrown as Zend_XmlRpc_HttpException. If this is not desirable for some reason, a doRequest() method provides a way to work with request and response objects directly.

    Update: This post was featured on PHPDeveloper.org.

  • Best Practices of PHP Development Oct 30, 2006

    Posted by Mike Naberezny in PHP,Testing

    Slides from my ZendCon 2006 session are now available:

    It is a new, three hour talk that I developed and presented together with Matthew Weier O’Phinney. This is the second opportunity that Matthew and I have had to team up for a session at ZendCon and it was a great time again.

    Update: You might also like to check out the updated presentation that we gave at ZendCon 2008.

  • Introducing Zend Framework Oct 24, 2006

    Posted by Mike Naberezny in PHP

    The April 2006 issue of php|architect magazine featured my article, “Introducing Zend Framework“. It can now be downloaded in PDF format. Thanks to php|architect for making it available for free.