Negative number PHP array indexes, var_export and WTF

Those folks that know me in the programming, web development or technology context know that I am a PHP fanboi to the nth degree. I eat, sleep, breath and live PHP. It is my very favorite programming language and it is the language that I learned how to program in. I stand behind it and have defended it – often – against the attacks of many a strict-type-language zealot from the world of .NET or Java or even Ruby. Seriously, I love PHP with all of $my <3;

However, these same people that know my insane and indescribable love for "my" language also know that I am usually very fast to point out some of it's major stupidities and illogical implementations. Which comes first, the $haystack or the $needle? Is it a str_* function or a str* function? Are the array function args passed by reference or am I expected to handle a return? There are so many of these little issues with PHP that sometimes I, myself, have no choice but to ask... WTF?

Today is one of those days. I am working on a bug for work in which the number -99 is somehow magically being transformed into -9223372036854775808 and is causing significant problems for our application. In doing some trouble shooting, I discovered that, as part of our process of caching some information, we use the var_export() function to write out an array to a file and somewhere between the passing of the data to var_export and the file that the exported data is written to, the -99, when used as an array index, suddenly became 18446744073709551517. This did not happen when -99 was the value of a scalar variable nor when it was a value assigned to an object property.

Looking a little closer I found that this particular server was running PHP 5.2.17 on CentOS, so I decided to dig even deeper and try this on other versions of PHP. On my 5.3.6 version of PHP on my Mac I could not reproduce the issue. But I was able to reproduce it on 5.2.17 on my Mac. My colleague was likewise able to reproduce it on 5.2.10 on his Ubuntu installation. And I was able to reproduce it on several PHP versions using 3v4l.org.

I'm not exactly sure what is going on under the hood, but my suspicion is that because PHP does not support unsigned integers it needs to convert the signed int -99 to an unsigned value in order to store it in the symbol table. I suspect when var_export is called, this unsigned value is being returned rather than the signed value. At the very least, this is an issue that will more than likely never be corrected since PHP 5.2 is now out of date and this problem, as far as I can tell, does not expose itself in 5.3 save for 5.3.3.

Regardless, if you want to see this for yourself and you have a 5.2 build laying around somewhere (or a 5.3.3 build), give this little snippet a shot and see what you get:

<?php
for ($i = 10; $i > -101; $i--) {
    echo "$i...\n";
    $q = array($i => 'this');
    var_export($q);
    echo "\n";
}

Or, if you just want to see it without a bunch of output, try this:

<?php
$a[-99] = 'bilk';
var_export($a);

As an added bonus, take the broken translated value and use that as an array index, then var_export that. You might pleasantly surprised by what you see I'd bet.

All of this is to say, if you are still using PHP 5.2 - and let's be honest, who is really using PHP 5.2 any more aside from those that have it on a test server - and you are using var_export on an array with signed int indexes, you are probably not going to get what you expect out of it. You have been warned.

Also? WTF PHP?