I don't know John Lim, but he linked to a Livejournal post where someone complained about their expectations being dashed when trying various comparisons.
<?php
$a = 0;
$b = "eggs";
$c = "spam";
print ($a == $b) ? "a == b\n" : "a != b\n";
print ($b == $c) ? "b == c\n" : "b != c\n";
print ($a == $c) ? "a == c\n" : "a != c\n";
print ($a == $d) ? "a == d\n" : "a != d\n";
print ($b == $d) ? "b == d\n" : "b != d\n";
print ($c == $d) ? "c == d\n" : "c != d\n";
?>
% php equality.php
a == b
b != c
a == c
a == d
b != d
c != d
They proceed to be pretty confused by what could be perceived as confusing behavior. PHP does some type juggling in the background.
First, let's examine what happens when we cast various common values as booleans. There are two type specifiers because I specify each item as the type and the value, and then cast that.
/* Plain old true and false values */
(boolean) (boolean) true === (boolean) true
(boolean) (boolean) false === (boolean) false
/* A NULL, which is a special value */
(boolean) (NULL) NULL === (boolean) false
/* An empty string */
(boolean) (string) '' === (boolean) false
/* The numbers zero and one */
(boolean) (integer) 0 === (boolean) false
(boolean) (integer) 1 === (boolean) true
/* Other non-zero numbers (this behavior is just like C) */
(boolean) (integer) -1 === (boolean) true
(boolean) (integer) 100 === (boolean) true
/* The number zero in string form: the string zero */
(boolean) (string) '0' === (boolean) false
/* An empty array */
(boolean) (array) array() === (boolean) false;
/* Non-empty arrays */
(boolean) (array) array(0) === (boolean) true;
(boolean) (array) array(1) === (boolean) true;
(boolean) (array) array(0, 1) === (boolean) true;
/* A non-empty string */
(boolean) (string) 'in the hay' === (boolean) true
/* A tricky non-empty string */
(boolean) (string) 'false' === (boolean) true
/* Really tricky non-empty strings
* I might actually take issue with these,
* because they are really sneaky, but
* what is (probably) happening is that
* first the strings get converted into integers
* and then booleans.
*/
(boolean) (string) '0 is awesome' === (boolean) true
(boolean) (string) ' 0' === (boolean) true
/* That notion seems to be help up by this test: */
(boolean) (string) '1' === (boolean) true
/* Fortunately, it is not completely ridiculous */
(boolean) (string) 'awesome is 0' === (boolean) true
So what is going on in that "crazy" example? One of the things to point out is that non-empty non-numeric strings are being compared to the number zero. My guess is that the zero is being juggled into a string since the string cannot be juggled into a number.
<?php
$a = 0;
$b = "eggs";
$c = "spam";
/*
(string) $a is '0';
(string) $d is 0 (because it is not set)
(string) $d is '' (because it is not set)
*/
print ($a == $b) ? "(string) a == (string) b\n" : "(string) a != (string) b\n";
print ($b == $c) ? "(string) b == (string) c\n" : "(string) b != (string) c\n";
print ($a == $c) ? "(string) a == (string) c\n" : "(string) a != (string) c\n";
print ($a == $d) ? "(int) a == (int) d\n" : "(int) a != (int) d\n";
print ($b == $d) ? "(string) b == (string) d\n" : "(string) b != (string) d\n";
print ($c == $d) ? "(string) c == (string) d\n" : "(string) c != (string) d\n";
?>
% php equality.php
(string) a == (string) b
(string) b != (string) c
(string) a == (string) c
(int) a == (int) d
(string) b != (string) d
(string) c != (string) d
I wouldn't mind a more strongly typed language sometimes, and I might have made different design decisions, but they were made for a reason.
Another site on the internet lamented the fact that strpos() returns a false on failure and a 0 if the string match happens at the zero index, complaining that the required code is not very clear.
if (false !== strpos('haystack', 'needle')) {
echo 'Found it!';
}
Their comment was that this (the C syntax) would be oh-so-much-better:
if (-1 < strpos('haystack', 'needle')) {
echo 'Found it!';
}
Wow. That's so much clearer! I suppose that the meat of their problem was that one has to use the !== operator instead of the != operator to check for false. Yes, strpos is kind of a hassle that way, but if it really bothers you, it is trivially easy to write a wrapper function.
/* Note that I am Elliot-Smithing the argument order */
function needle_in_the_hay($needle, $haystack) {
return (false !== strpos($haystack, $needle);
}
The real problem here is that strpos in C is for finding a single character in another string and is being abused in php to find whole strings in other strings. Better to pick a new name for that purpose. Even so, ultimately it's just an excuse to whine about PHP. It's not a perfect language, but it is what it is.
You could really make the complaint that there should be a String class with methods and stuff like that. I would accept that complaint... and then ask why you aren't writing that class. You know you want to!
Oh, php has a nice chart of comparisons.