Unlike probably every other language on the planet, PHP decided to share a common type for hashes and arrays.
<pre>
$a = array(4, 6, 9);
$b = array('foo' => 4, 'bar' => 6, 'blah' => 9);
</pre>
A major issue with that mess is that with functions like array-merge(), PHP will reinvent the indexes if it finds that the current indexes look like numbers, even though you intentionnally used strings to get real hash keys.
<pre>
$a = array('1357' => 10, '9753' => 20);
$b = array('2468' => 30, '8642' => 40);
$c = array_merge($a, $b);
var_dump($c);
</pre>
Guess what you get with such a code?
<pre>
array(4) {
[0]=>
int(10)
[1]=>
int(20)
[2]=>
int(30)
[3]=>
int(40)
}
</pre>
Hey? 0, 1, 2, 3? Yes, because keys like ‘1357’, although strings, were detected as integers and PHP decided to reinvent the indexes. Wotta mess.
- Workaround #1: switch to a clean language with no silly surprises, like Ruby:
a = { 1357 => 10, 9753 => 20 }
b = { 2468 => 30, 8642 => 40 }
p a.merge(b)
Result:
{8642=>40, 9753=>20, 2468=>30, 1357=>10}
- Workaround #2: add a dummy char before the first digit, like a space, so that PHP doesn’t mess the indexes.
Notice the space before the digit in keys:
<pre>
$a = array(' 1357' => 10, ' 9753' => 20);
$b = array(' 2468' => 30, ' 8642' => 40);
$c = array_merge($a, $b);
var_dump($c);
</pre>
Result:
<pre>
array(4) {
[" 1357"]=>
int(10)
[" 9753"]=>
int(20)
[" 2468"]=>
int(30)
[" 8642"]=>
int(40)
}
</pre>
Woah, wonderful.
But are those keys actually strings? Given the behavior of array_merge(), yes. But with operators, they aren’t, they can be used just as if they were integers:
<pre>
$a = ' 42'; # notice the space
$b = ($a == 42);
$c = $a * 2;
var_dump($b);
var_dump($c);
</pre>
Result:
bool(true)
int(84)
How logical…
empty() is also a good joke, btw. Why the hell does empty() evaluates as TRUE with 0, 0.0 and “0”, but not with “-0” nor “0.0”?