Undefined Constant Is a String?

From the I-noticed-this-one-day-while-looking-at-a-co-worker’s-code department comes a tale about the use of undefined constants in PHP – and relying on this twisted “feature” to make an application function properly.

So, there I was, looking over the shoulder of a colleague, trying to help him debug an application, when I saw something that struck me as quite odd.

“Where is that constant defined?” I asked, pointing to the screen.

“What constant?”

It was plain as day to me. “That constant.”

“Oh, that’s not a constant. It’s a string.”

“No, it’s not,” I retorted. “If it’s a string, why are there no quotation marks. You should be getting an error about an undefined constant.”

“No, it’s a feature of PHP. You don’t have to use the quotation marks.”

And then it struck me: If this is a feature, it’s most likely the dumbest feature I’ve ever seen. Perhaps Jamie of Yet Another Web Development Blog has something there…

Nevertheless, after digging around some, I found this in the PHP manual:

If you use an undefined constant, PHP assumes that you mean the name of the constant itself, just as if you called it as a string (CONSTANT vs “CONSTANT”). An error of level E_NOTICE will be issued when this happens. See also the manual entry on why $foo[bar] is wrong (unless you first define() bar as a constant).

PHP Manual: Constants > Syntax

Hmm. So, if $foo[bar] is wrong, remind me again why this is even a feature? In my opinion, it should return, at the least, an E_WARNING error. Instead, the error level is E_NOTICE, but let’s examine what happens when the millions of people running distribution versions of PHP use this “feature.”

Most distributions use the php.ini-dist file instead of the php.ini-recommended file. This means that error_reporting is set to E_ALL & ~E_NOTICE and notices are not generated or displayed, so users will never know about their undefined constants. My colleague was using the PHP distribution for Debian, Debian’s default php.ini settings, and, thus, was never aware of the notices generated by the use of undefined constants. What’s worse is that the code my colleague was using was not his own – it was third-party, open source software!

Here’s why it’s bad to rely on this behavior. In the follow snippet of code, I expect that foo will always be the string “foo.” The problem is that I’m really using an undefined constant.

$var = foo;

When I pass $var to my_func(), the function may do something that expects the value to be the string “foo,” but what if the core developers decide to add a constant with the name foo and assign it a value. Now, $var is no longer the string “foo.” It’s whatever the language has defined it to be. That’s an unlikely scenario, but what if another programmer in my team decides to define the constant foo (this is much more likely)? Now, the code mysteriously breaks, and it’s difficult to find the problem (especially because E_NOTICE is turned off). Even worse: what if I’m using third-party code that relies on this behavior, and I’ve integrated it into my application that has some global constants by the same names set?!

So, the lessons learned from this are:

  1. Always develop applications using an error level of E_ALL or E_STRICT; when you encounter notices, fix them because they could indicate problems with your logic that may not immediately present themselves
  2. If you want a string value, use quotation marks (single or double), otherwise, treat your “string” as a constant because that’s what it is
  3. Don’t rely on the use of undefined constants – they aren’t NULL or empty; instead, they are actually the string value of the constant name

Note that this behavior of constants continues to exist even in the latest versions of PHP, including 5.2 and 6.0.0-dev. Why? I don’t know.