24 Jan

PHP: Be careful with global constants

Did you know that global constants, when undefined, evaluate to a string containing the constant name? Talk about a mouthful – here’s an example repurposed from the PHP docs:

<?php
define("CONSTANT", "Hello world.");
echo CONSTANT; // outputs "Hello world."
echo Constant; // outputs "Constant" and issues a notice.
?>

Depending on your programming background, this probably isn’t what you had in mind. Not me at least – all the languages I’ve ever dealt with fail when attempting to evaluate undefined constants.

That means that if you’re not careful, an undefined constant can cause bugs like this:

if ($user_level < ADMIN_LVL) { // Typo! Should be ADMIN_LEVEL
   // always evaluated
}

I’ve also seen permutations of the following:

define('DEBUG_MODE', true);

if (DEBUG) { // Yes, another typo
  // always executed -- aside: should use if_defined
}

There’s a couple defensive measures you can take. One, use an error reporting level of E_STRICT or E_ALL during development, which will emit a warning in the case above — if it’s evaluated. Better yet, stick to class constants. Undefined class constants throw good old fashioned errors, just like Ruby, Python, et al.

class Consts {
  const ADMIN_LEVEL = 5;
}

// Later that day ...

if ($user_level < Consts::ADMIN_LVL) { // Here's that typo again
  // throws an error
}

Failing fast like this could be the difference between having a bug reported to you immediately by your users, or having a bug reported to you 3 months later when errors pop-up in your database. Don’t know you guys, but I’ll take the first one.