Skip to main content

Assumptions and Errata: Two Quick Tips

First tip of the day: when reading any kind of technical book, one of the first things you should do is check the errata. This will save you time, hassle, and drywall repair costs.

Second tip of the day: don't assume. This is an infinitely more difficult tip to follow through on than the first, because most of the time, you don't even realize you're making an assumption.

A programming parable to illustrate: I'm new to Drupal module development, and was experimenting with restricting module features by node type. The method demonstrated by my guide in this inquiry, the excellent Pro Drupal Development, is quite straightforward:

  • Create an administration page for your module
  • Add a form to that page
  • Add a checkbox for each node type to that form

When the user visits the administration page, they tick off the node types that should have the feature. Then, when it comes time to view (or "render") a node, you just run a quick check in hook_nodeapi() to see whether this node is lucky enough to get your module's feature:

$allowedNodeTypes = variable_get('module_node_types', array('blog'));
if(in_array($node->type, $allowedNodeTypes)) {
  // Enable ground-breaking feature
}

The above sample is mostly correct ... mostly. Here is the correct version:

$allowedNodeTypes = variable_get('module_node_types', array('blog'));
if(in_array($node->type, $allowedNodeTypes, TRUE)) {
  // Enable ground-breaking feature
}

Had I checked the errata, or realized the implicit assumption I was making (more on that later), it would have saved me about 25 minutes of head-scratching. Read on to find out why you need that third parameter.

How Drupal Stores Variables

When you save a variable in the variable table, Drupal uses PHP to serialize the values so that they can be stored as a string (and hence, a single row in the database). The resulting string is extremely funny-looking. If as in our example you had a bunch of checkboxes, with one checkbox for each node type on your site, and you checked off the "blog" and "page" checkboxes, the serialized version of the checkboxes would look something like this:

a:3:{s:4:"blog";s:4:"blog";s:4:"page";s:4:"page";s:5:"story";i:0;}

While enigmatic at first, this string is nothing more than a series of key / value pairs. Here's the first pair. I added a pipe to visually separate the key from the value:

s:4:"blog"; | s:4:"blog";

The first half (before the |) is the key. The "s" means, "This key is a string". The "4" means, "It is four characters long". The "blog" means "blog" (it's the actual key). The second half is the value. It's the same as the key: the four-character string "blog".

If this were represented as an array, you'd have this:

array
  "blog" => "blog";

In fact, when you later unserialize this string by calling variable_get(), an array is what you get back.

What I Assumed

My erroneous assumption was that, since we were checking for the presence of a node type in an array, the array would only contain the node types that had been checked off. Given the (incorrect) code sample above, this was a reasonable assumption. But it was still an assumption – and it was still wrong.

Having a reasonable assumption that turns out to be wrong is kind of like being the innocent party in a car accident. Nobody blames you for the accident because it wasn't really your fault, but the damage to your car is still real. This is why people drive defensively. Since you have nothing to gain from being in a collision, regardless of who causes it, the best thing to do is to try to avoid the situation altogether. Assumptions are like big fat pieces of duct tape on your windows that prevent you from seeing road hazards, like toddlers driving stationwagons and other common dangers.

Back to our serialized string. Take a look at the last key / value pair:

s:5:"story";i:0;

This is where things get weird. When that value gets unserialized, it gets represented in PHP like this:

array
  "story" => 0

Note that the zero is an integer, not a string. This is the key to the whole mess, because it turns out that in_array() interprets integer zero as some kind of truthy wildcard. You can search for any non-numeric string in an array with integer zero as a value and in_array() will always return true. For instance:

$a = array("php" => "iguana", "python" => "rat", "MUMPS" => 0);
return in_array("thisIsNotInTheArray", $a);
// returns true

Like many other things in PHP, I'm not really sure why it's like this. I mean, if anything, integer zero should always return false! That would at least make a little sense. Anyway, putting in_array() into "strict mode" makes it behave as you would expect:

$a = array("php" => "iguana", "python" => "rat", "MUMPS" => 0);
return in_array("anyStringAtAll", $a, TRUE);
// returns false

An interesting little excursion, to be sure, but I could have done without the furrowed brows.

Yep

This bit me too… what a dumbass function! :<

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.