PHP: Dispatch tables, an alternative to switch hell

Earlier this week I was putting together a block of code which ended turning into a switch statement with a tangled mess of long case blocks, complicated fall throughs, and ultimately became impossible to follow. Being a stand up guy, I decided to refactor the block using a technique where the case blocks are converted into anonymous functions, indexed into an associative array, and then the correct function is called depending on the value. I haven’t seen this show up too often in PHP code so I thought I’d share.

So what’s the problem?

The life of a switch statement usually starts out relatively benign, you have a few simple conditions and each block is relatively compact:

<?php

switch( $dayOfTheMonth ){
  case 1: 
   // do stuff
  break;

  case 15:
    // pay people
  break;

  case 30:
  case 31:
    // do stuff
  break;

  default: 
    // no op
  break;
}

But then, the switch grows and each case becomes complicated enough that it the entire block becomes mostly unreadable: Ellipsis for effect.

<?php

switch( $dayOfTheMonth ){
  case 1: 
   // do stuff
   // more crazy conditional logic
  break;
  case 2:
  // do stuff
  break;
  ....
  ....
  case 14:
  // do stuff
  // maybe a while loop  
  break;
  case 15:
    // pay people
  break;
  ...
  ...
  case 29:
  // do stuff
  // maybe a while loop  
  break;
  case 30:
  case 31:
    // do stuff
  break;

  default: 
    // no op
  break;
}

At this point, its hard to reason about what’s going to happen because each case statement has presumably gotten so large and different conditions are “falling” through so the side effects are difficult to trace through.

An alternative

An alternative to using a normal switch statement is to use a dispatch table, which is basically an array of functions indexed by whatever variable you’d normally be “switching” on. The primary benefit to structuring the code this way is that you can easily reason about side effects since the only variables that can be changed are what captures the return value or anything passed by reference. In addition, since every case is a separate function its a bit easier to edit the code. So what does this look like? It’s actually pretty straightforward:

<?php

$dayFunctions = array(
  1 => function(){
    // do stuff
    return "something";
  },

  2 => function(){
    // do stuff
    return "something";
  },

  ...

  15 => function(){
    // pay people
    return "something";
  },

  30 => function(){
    // do stuff
    return "something";
  },
);

// Make 31 the same as 30
$dayFunctions[31] = $dayFunctions[30];

$res = array_key_exists($dayOfTheMonth, $dayFunctions) ? $dayFunctions[$dayOfTheMonth]() : null;

Extending from there, you could also call the function with arguments, potentially by reference, and even have all the functions be closures which capture the variables to avoid having to call with arguments.

Anyway, questions or comments always welcome.

A modest proposal for how we can fix WordPress

Last month, a post started making the rounds on the internet decrying the dire state of the WordPress codebase. James highlights several legitimate gripes but unfortunately he muddles the discussion by mixing major problems with otherwise minor concerns. Another problem, is that James’ post considers the issues purely from a technical perspective but ultimately business concerns are going to motivate a drastic change in WordPress. Looking at James’ post and from my own run ins with WordPress, the biggest problems with WordPress as it exists now are:

Broken data model: As James pointed out, as people have started to use WordPress like a CMS with by adding things like custom post types and plugins it’s clear that the underlying data model is too rigid to properly support this need. The result of this, is that developing custom database functionality is notably difficult and it limits the types of extensions that can be built purely inside WordPress.

Limited separation of concerns: Throughout WordPress, globals are heavily used, templates are free to interact with the database, and there’s generally no concept of MVC separation. Apart from being confusing, this makes it difficult to effectively reason about the behavior of a WordPress install, making “smart” caching impossible. Additionally, it makes it difficult for dedicated “frontend” developers to work on templating since they’re often left juggling PHP code. Both of these issues ultimately make running a WordPress site more expensive since you’ll need more resources for operations and development.

No OO/Encapsulation, No Namespaces, No API: Owing to its PHP4+ heritage, the core WordPress code is entirely procedural and because of this every function touches the global namespace. Also, WordPress doesn’t have native support for serving as an API backend and exposing its data in different formats or interacting with non-browser clients. The OO and namespace issue is largely technical but it makes it difficult to develop modular WP components or mixin off the shelf PHP packages. The lack of a robust API makes it impossible to use a single WordPress installation to serve content on the web but also serve as a service for mobile clients, which ultimately limits its utility.

So how do we fix it?

“Fixing” an application as large as WordPress is obviously a herculean undertaking, especially because of the need to balance the existing ecosystem with the need for a clean, strong foundation. The reality is that modernizing WordPress is ultimately going to require a full rewrite but I think it could be strategically orchestrated to win community support for the backwards compatability breaks.

Without further ado, here’s how I would do it:

June ’13 - Release Twig for Wordpress

Twig for WordPress is a fully featured implementation of the Twig templating engine for WordPress. It allows developers to write WordPress themes in Twig instead of mixing PHP and HTML. Along with Twig, the plugin includes modern template caching techniques like partial page rebuilds and ESI support. In order to leverage Twig and its related benefits, developers have to write their themes with reasonably strict View/Controller separation since variables must be explicitly passed to Twig templates.

Theme designers are initially hesitant but once they see how much easier tracing the structure of Twig templates is versus straight PHP they’re converts. Developers are also fans since they enjoy being able to make the necessary page variables available in a template and then hand pages off to be themed. Benchmarks are done. Hackathons are sponsored. Themes are converted to Twig.

September ’13 - Release Doctrine Power Tools (DPT)

Leveraging Doctrine2, DPT enhances WordPress by augmenting it with the Doctrine2 ORM and associated “power tools”. This allows developers to seamlessly create new MySQL tables and then automatically generate administration CRUD for those tables. In addition, custom plugin code can choose to leverage Doctrine2 to interact with the new tables. With DPT, WordPress administrators are also able to design custom forms to insert data into custom tables and then filter and export the data in these tables.

Developers familiar with ORMs are immediately excited and after they try it out they’re hooked. They start evangelizing DPT in the community because it takes the drudgery out of creating custom database functionality in WordPress. Enterprise users slowly get wind of it and adopt it as well since it empowers their marketing team to do more without involving developers. WordPress has an ORM. Everything isn’t being stuffed into wp_posts.

January ’14 - Release WP Paladin Alpha

WP Paladin is a PHP 5.3+ object oriented rewrite of WordPress with an additional “compatibility layer” which provides compatible legacy plugins and themes access to the normal WordPress API. From a user perspective, Paladin has the same installation procedure, Admin UI, and basic functionality as stock WordPress. Additionally, a handful of the most popular plugins have been ported to be 100% compatible with Paladin. Technically, WP Paladin shares several key Symfony2 components with Drupal 8, notably the HttpKernel, which allows interoperability with other apps using HttpKernel. It also supports Twig templating and ships with the Doctrine2 ORM and DPT.

Since Twig for WP was released in June ’13, dozens of Twig themes have become available and early adopters are eagerly experimenting with Paladin. Although it currently only supports a handful of traditional WordPress plugins, it’s faster, easier to develop on, and plays well with others. The excitement is palpable. Blog posts are written. SXSW tickets are bought.

March ’14 - Release WP Paladin Beta

WP Paladin Beta is similar to the initial release except the “compatibility layer” has been removed, critical bugs have been fixed, and the platform is significantly more stable. The beta version is launched at an exclusive SXSW party to a frenzied mob. It’s taken a little less than a year, but the WordPress codebase has been modernized and new features have added. Additionally, the most popular WordPress themes and plugins have been ported to be compatible with the Paladin codebase.

The download counter hits 1 million by the end of SXSW. Congratulations are in order. VC Money is raised.

Great, count me in!

Doing something like this would certainly be a great way to “earn your stripes” but ultimately it’s going to end up burning thousands of man hours for an unknown payoff.

But who knows, maybe a company with deep pockets, talented engineers, and a disposition for risk will give it the ole college try.

PHP: Some thoughts on using array_* with closures

The other day, I was hacking away on the PHP backend for the “Startup Institute” visualization and I realized it was going to need a good deal of array manipulation. Figuring it was as good a time as any, I decided to try and leverage PHP 5.3+ new closures along with the array_* functions to manipulate the arrays. I’m not well versed with functional programming but I’ve used Underscore.js’s array/collection functions so this is mostly in comparison to that.

The Array

The entire shebang is on GitHub but here is the gist of what we’re intersted in:

There is a CSV file that looks like ssdata.csv.sample except with more entries that is read into a list ($data) where every object has keys cooresponding to the values in the header. Thinking in JSON, the array ends up looking like:

[

{"fname": "Ashish", "lname": "Datta", "track": "dev", "email_address": "ashish@setfive.com"},

{"fname": "Matt", "lname": "Daum", "track": "dev", "email_address": "matt@setfive.com"}

...

]

Ok great, but now what can we do with it?

Sorting:

Using the usort function is particularly natural with closures. Compare the following:

<?php

/* Without closures: */

class ArraySorter {

  public static $sortKey = "";

  public function sort($a, $b){
    return strcmp($a[ ArraySorter::$sortKey ],  $b[ ArraySorter::$sortKey ]);
  }

}

ArraySorter::$sortKey = $sortKey;

usort($data, array("ArraySorter”, "sort”));


/* With closures: */

usort($data, function($a, $b) use($sortKey) {

  return strcmp($a[ $sortKey ],  $b[ $sortKey ]);

});

It’s pretty clear the version with closures is much shorter, more conscience, and ultimately easier to follow. Being able to “capture” the local $sortKey variable is also a key feature on the closure version since with the static version there’s no easy way to introduce variables into the sorting function.

Mapping:

In the linked example, I used array_map to basically convert an array of characters into an array of ASCII values for those characters.

<?php

/* Without: */

for($i = 0; $i < count($data["first_name"]); $i++){

 $data["first_name"][$i] = ord($data["first_name"][$i]);

}

/* With: */

$data["first_name"] = array_map(function($el){ return ord($el);}, $data["first_name"]);

With such a small map function, it’s hard to see or appreciate the benefits of using the closure along with array_map. With the closure though, you’ll get a couple of benefits including isolated scope so that you won’t inadvertently rely on the value of a variable that isn’t directly related to transforming the array values.

Using the closure would also “look” much cleaner if the array had non-numeric keys, since without being able to use integer indexes the for(…) loop would be more confusing.

Filter it:

This isn’t used but it could have been to return only the elements that were selected.

<?php

/* Without: */

$filteredArray = array();

foreach( $payload as $item ){

 if( (strlen($filterEmailAddress)

      && $item["email_address"] == $filterEmailAddress)

     || in_array($item["track"], $selectedTracks) ){

    $filteredArray[] = $item;

 }

}


/* With: */

$filteredArray = array_filter($payload, function($item) use ($filterEmailAddress, $selectedTracks){

 return ((strlen($filterEmailAddress)

            && $item["email_address"] == $filterEmailAddress)

            || in_array($item["track"], $selectedTracks));

});

Looking at the the version with the closure, its a bit easier to follow and since it’ll enforce scope isolation if the “truth test” was a bit more complicated you’d only have to debug what’s actually inside the closure. Also, not having to “skip” some elements leaves the code with a nicer feel and overall I’d argue its just better looking.

Overall Thoughts:

Overall, using closures with the array_* functions will definitely lead to cleaner, more concise, and easier to follow code. Unfortunately, there are a few rough spots. Like with most of the standard library, the argument order is inconsistent which is always a constant irritation. For example, for no apparent reason array_map is “callback, array” but array_filter is “array, callback”. Also, another irritation is that the “index” isn’t available inside several of the callbacks like on array_reduce or array_map.

Personally though, the biggest limitation is that none of the array_* functions will work with classes that implement the Traversable or Iterator interfaces. That means if you have a Doctrine_Collection and you want to reduce down to a single result you’re still stuck with a foreach(…).

Anyway, as always I’d love to hear other opinions in the comments.

Symfony2 and Ordering of Relations and Collection Form Fields

Recently I was working on a project where I kept finding myself ordering a relation over and over by other than something than ID order (ie id= 1,2,3,4,5). For example, I always wanted my relation to be ordered by the ‘name’ field, rather than the ID or order it was inserted into the DB. Let’s take this schema as an example:

CREATE  TABLE IF NOT EXISTS `post` (
  `id` INT NOT NULL AUTO_INCREMENT ,
  `name` VARCHAR(32) NULL ,
  PRIMARY KEY (`id`) )
ENGINE = InnoDB


CREATE  TABLE IF NOT EXISTS `post_attachment` (
  `id` INT NOT NULL AUTO_INCREMENT ,
  `name` VARCHAR(32) NULL ,
  `url` VARCHAR(32) NULL ,
  `post_id` INT NOT NULL ,
  PRIMARY KEY (`id`) ,
  INDEX `fk_post_attachment_post_idx` (`post_id` ASC) ,
  CONSTRAINT `fk_post_attachment_post`
    FOREIGN KEY (`post_id` )
    REFERENCES `post` (`id` )
    ON DELETE CASCADE
    ON UPDATE CASCADE)
ENGINE = InnoDB

The issue is each time I attempted:

<?php
$attachments = $post->getPostAttachments();
foreach($attachments as $attachment)
{
     echo $attachment->getId().' '.$attachment->getName()."\n";
}

//Output
// 1 d name
// 2 c name
// 3 a name
// 4 b name

I wanted the output to be in alphabetical order for example. To make this the default for that relation you can add the following annotation to your ‘Post’ entity:

<?php
//MyBundle/Entity/Post.php
...
class Post
{
    ...
    /**
     * @ORM\OneToMany(targetEntity=PostAttachment",mappedBy="post")
     * @ORM\OrderBy({"name"="ASC"})
     */
     private $post_attachments;
    ...


}

Now if you do “$post->getPostAttachments()” they’ll be automatically in order. The ‘@ORM\OrderBy’ column takes care of the ordering automatically. You can specify as many columns on the relation as you’d like there. In addition, this will make it so that all form collections on post with post_attachments are also ordered by name, rather than ID. This affects the relation call every time. If you are only looking into having it some of the time, look into using the repository to do the ordering for those calls.

Behat and Symfony2 - A Simple Gotcha

Recently we were using Behat on a new project with the Symfony2 extension. It took a bit to get it up and running correctly as the docs (for the extension setup) seem to be incorrect. First place the behat.yml directly in the project root. Second, when using the “@” notation to reference your bundle you need to be sure to enclose it in quotes. For example, ‘bin/behat –init “@MyBundle”’. Without the quotes it will not be parsed correctly and will not setup the structure as you want.

If you are running into the following error:

  [RuntimeException]                                                         
  Context class not found.                                                   
  Maybe you have provided a wrong or no `bootstrap` path in your behat.yml:  
  http://docs.behat.org/guides/7.config.html#paths     

Most likely the initial setup didn’t go correctly. We kept having that issue whenever we added the behat.yml to our root directory, but then didn’t use the quotes to enclose the @MyBundle. Hopefully this saves you the headache!

I’ve shot over a pull request to the main behat repo for the extension so it hopefully will be fixed soon:

Happy testing!