Thursday, September 23, 2010

PHP: What equals zero, but is not empty?

In a project we did recently, we needed to check if a SHA1 hash was correctly being set. We at first tried it with the PHP empty() function. If the hash turned out to be empty, we threw an exception. However, we found out that somewhere along the way, the hash sometimes was 0 (zero). So we added another check to see if the hash was 0. If it was, we threw another exception, so the code looked something like this:
if (empty($hash)) {
    throw new Exception('Hash is empty');

if ($hash == 0) {
    throw new Exception('Hash equals 0 (zero)');

Nothing really fancy, right? Well, as it turned out, we got a lot of exceptions, saying the hash equals 0 (zero). But why? What was going on? What obvious mistake laughed us in the face, while we looked over it?

My astonishment only grew, when I took a look at the PHP manual about the empty() function. It clearly says that 0 as an integer and "0" as a string are considered to be empty. How on Earth can a hash be equal to 0, but not be empty? That's pretty impossible, according to the rules of logic. That is, until you realize that you are developing in PHP.

Some further research learned that, in PHP, if you parse a string to an integer and if "the string starts with valid numeric data, this will be the value used. Otherwise, the value will be 0 (zero)." source Yes, indeed. That means that if you have a string and that string starts with any non-numeric character or with a zero followed by any non-numeric character, and you compare that string to 0, it will return true. In short:
echo ("a9993e364706816aba3e25717850c26c9cd0d89d" == 0); //true
echo ("0e226ad77382bda133797db656efd5e8d1099014" == 0); //true
echo ("47425e4490d1548713efea3b8a6f5d778e4b1766" == 0); //finally, false!

I'm starting to believe that the first P in PHP stands for something that has to do with Pain...