Baby, Don't You Loose Your Type On Me

Photo of Greg Harvey
Fri, 2008-08-29 18:30By greg

Many programmers from beyond the realm of PHP, deep in the black country where the dragons reside, whinge like an Australian swim-coach about PHP's loose variable typing. Many PHP developers either don't know what this means or don't care. I didn't much care, until recently, where I got a practical lesson in why loose typing can, on ocassion, really suck.

Here are some interesting effects of PHP's loose typing:

$var1 = 1;
$var2 = '1';
print 'Result: '.($var1 == $var2);
?>

And it prints 1 (in other words true) even though the first variable is an integer and the second a string. Here's another interesting one:

$var1 = 0;
$var2 = false;
print 'Result: '.($var1 == $var2);
?>

True again! Even though the first variable is clearly an integer and the second is clearly a boolean.

And here's the gotcha I had. Picture this array:

$loose_typing_sucks = array(
'Loose',
'Typing',
'Can',
'Result',
'In',
'Severe',
'Hair',
'Loss',
);
?>

Now look at this PHP code:

if (array_search('Hair', $loose_typing_sucks)) {
print 'Array Key Is: '.array_search('Hair', $loose_typing_sucks).'
';
print 'Array Value Is: '.$loose_typing_sucks[array_search('Hair', $loose_typing_sucks)];
}
?>

According to the array_search documentation, it returns false if it finds nothing, so that should work, right? And it does - try it.

But what about this?

if (array_search('Loose', $loose_typing_sucks)) {
print 'Array Key Is: '.array_search('Loose', $loose_typing_sucks).'
';
print 'Array Value Is: '.$loose_typing_sucks[array_search('Loose', $loose_typing_sucks)];
}
?>

Oooh, it prints nothing. But 'Loose' is in the array. What the deuce?

array_search also returns the array key if it finds something and what's the array key for 'Loose'? Zero!

Scroll up and remind yourself of my second example and all becomes clear. The 'if' is not evaluating because it is reading an array key of zero as false. Horrible!

But all is not lost. In PHP you can enforce strict typing. Try this out:

$var1 = 1;
$var2 = '1';
//notice there are three 'equals'
print 'Result: '.($var1 === $var2);
?>

It now returns false. That's better. Similarly, I get a true from this:

$var1 = 1;
$var2 = '1';
print 'Result: '.($var1 !== $var2);
?>

So if I apply that to my array_search issue, I can use strict typing to do this:

if (array_search('Loose', $loose_typing_sucks) !== false) {
print 'Array Key Is: '.array_search('Loose', $loose_typing_sucks).'
';
print 'Array Value Is: '.$loose_typing_sucks[array_search('Loose', $loose_typing_sucks)];
}
?>

It works!! =)

Just to prove it, try a non-existent value:

if (array_search('Foo', $loose_typing_sucks) !== false) {
print 'Array Key Is: '.array_search('Foo', $loose_typing_sucks).'
';
print 'Array Value Is: '.$loose_typing_sucks[array_search('Foo', $loose_typing_sucks)];
}
?>

So you can (and I would argue you always should, unless there's a really good reason not to) enforce strict typing when doing all variable comparisons, avoiding lazy options such as !$variable to indicate a boolean false.

The other thing you should do, though no PHP developer (myself included) does, is properly declare and type your variables before you need them, for example:

$flag = (bool) true;
?>

If you set error_reporting to E_ALL in your php.ini file then PHP will issue a notice message if you don't declare variables properly and just try and compare them on the off chance they were created somewhere (a common technique with PHP). There's a good note on it here:
http://p2p.wrox.com/topic.asp?TOPIC_ID=7613

Drupal wants to head towards being E_ALL compliant, so getting in to some good habits would be well worthwhile, unless you want to have to hack at the default .htaccess file to prevent all the warnings on your page caused by your sloppyness! Or fix them (heaven forbid).

I should practice what I preach. Meh.

For the younger readers, music lesson - title derived from:
http://www.google.co.uk/search?q=james+taylor+loose+your+lip