I worked at a company where we were replacing the user-facing component of our giant, ugly PHP storefront with a Rails version; in doing so, our developers implemented a JSON bridge between the two, allowing the frontend and backend to operate separately, using separate databases (and actually, they were in separate data centres).
As we were testing, we found that some products in our database would cause a JSON decoding error on the Rails side. After a few minutes, we realized the problem. We had a string field for something (product IDs, manufacturer SKU, etc). On the PHP side, the JSON encoder was using PHP's is_numeric() for each field to see if the field was a number (to determine how to encode it). Some of the SKUs, however, happened to be composed entirely of digits, and for those, PHP encoded them into the JSON as integer values. This, of course, broke on the Rails end, because Rails was expecting a string value and got an integer value.
In the end, we had to write a surprising amount of code to work around the brain damage involved, since regardless of what we tried to do PHP wanted, by default, to send things as integers whenever possible. I believe the final fix was to actually patch the JSON encoder library and special-case that field.
Heh. I recently had a password reset function break. Problem not reproducible on the test system. Turns out the reset email is produced by a Freemarker template engine, which is "smart" about datatypes: "oh, a number! I need to Format that nicely with commas to separate the thousands!" Too bad that number was the user ID - Not a problem on the test system with its 300 users, but in production...
is_int() checks the type of the field, while is_numeric() looks for strings that look like numbers.
You will also need to use settype() when getting your data from the database since integers from the database will pass through as strings (since the database range and PHP range aren't necessarily the same, use a float if you need unsigned ints).
(I assume that "what." is a request for an explanation.)
A float can store an exact integer of up to 53 bits even on a 32 bit machine.
PHP only has signed ints. If you need to store an unsigned int you can either store it internally as signed and only convert it to unsigned with printf() when you output it (and deal with the complexity of comparisons), or use a float and limit yourself to 53 bits.
If you have a 64 bit machine then of course you can easily fit an unsigned 32 bit int in that range. But it's wise not to rely on that at least for another few years.
In short, if you need more than 32 signed bits of range, and you want to make sure your code will run on any machine, then use a float. If you know you only use 64 bit machines then you have more flexibility. (You can use PHP_INT_SIZE and PHP_INT_MAX to check.)
If you need even more range than that then use the built in GMP library.
Also, PHP will automatically convert numbers that are too large from ints to float, so normally you don't see any of this. It's only if you use settype() to force an int that you have to pay attention to this.
could you have added some text at the end of the id before sending it and then removed the extra bits from the end on recieving side? something like a parity value.
That would probably work, but it means that the problem + workaround is spread out across two systems rather than being contained in just one. Also, working around it on the consumer side means that any new consumers (or any new string fields!) will need to use the workaround too, further spreading out the problem. Better to keep it encapsulated in one system if possible.
If you have a method that breaks when an int is passed in, just seems like good defensive programming to call to_s in Ruby. Any other caller could make the same mistake. But, I also understand/agree with fixing the root issue for the sake of other clients.
As we were testing, we found that some products in our database would cause a JSON decoding error on the Rails side. After a few minutes, we realized the problem. We had a string field for something (product IDs, manufacturer SKU, etc). On the PHP side, the JSON encoder was using PHP's is_numeric() for each field to see if the field was a number (to determine how to encode it). Some of the SKUs, however, happened to be composed entirely of digits, and for those, PHP encoded them into the JSON as integer values. This, of course, broke on the Rails end, because Rails was expecting a string value and got an integer value.
In the end, we had to write a surprising amount of code to work around the brain damage involved, since regardless of what we tried to do PHP wanted, by default, to send things as integers whenever possible. I believe the final fix was to actually patch the JSON encoder library and special-case that field.