Frank DENIS random thoughts.

PHP and its horrible hash/array mixup

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”?