PHP Returning Numeric Values in JSON

When I wrote about launching a prototype of a new joind.in API, quite a few people started to try it out. My friend David Soria Parra emailed me to point out that many of the numbers in the API were being returned as strings. He said:

It's just a standard problem of PHP REST services. When I try to access it with java I have to convert it over and over again to ints.

I did have a quick look at the PHP manual page for json_encode but I didn't see anything mentioning this. A few weeks later (my inbox is a black hole and it takes a while to process these things) I fell over a throwaway comment to an undocumented constant JSON_NUMERIC_CHECK, and I added the constant name to my todo list. In the time it took for me to actually get around to googling for this, some wonderful person updated the PHP manual page (this is why I love PHP) to include it as a documented option, and someone else had added a user contributed note about using it.

It turns out, this constant does exactly what I need. Here's a simple use case:

echo json_encode(array('event_id' => '603'));
echo json_encode(array('event_id' => '603'), JSON_NUMERIC_CHECK);

and the output:

{"event_id":"603"}
{"event_id":603}

There are probably some situations in which you don't want all your looks-like-a-number data to be returned as a number, but for now it seems to be a good fit for api.joind.in.

14 thoughts on “PHP Returning Numeric Values in JSON

  1. The problem lies not in json_encode, it lies in '603'. Obiously it is a string, not a number. With a number, it works as you want to. For example:
    echo json_encode(array('event_id' => 603));
    renders to
    {"event_id":603}

    So the question is: Where does the '603' come from? That's the interesting part!

  2. GodsBoss: In this case it's the result of pulling data from the database into an array and then into json_encode from there. I can imagine string values coming from forms too (for example).

    • Okay, if form data is put directly into json_encode (should be safe), that can happen (although it's not something I would encounter). But database data? Numeric values should be numbers in the database, not strings.

      • Even for numeric column types in a mysql, PDO returns data as strings by default, which is why I was originally sending them as strings, and why I used strings in my example code.

        • For PDO::query(), I honestly don't know (I do not use it), but for PDOStatement::bindValue(), although the default is string, it's possible to give it a parameter to determine its type and I strongly recommend that! Why should something which should be of a numeric type be a string?

        • Here's a very specific thought: as those are IDs, and not actually numbers (you're never going to perform a calculation on them), it actually makes a bit more sense to treat them as strings at every point past the database.

          If you're going to insert it back into a database, you're going to do conversion as part of the sanitizing of the data, but otherwise they are IDs. I suppose if you're doing comparison between two different retrieved sources (one that has typecast them to integers and one that didn't), you might run into a problem, but only if you're ==='ing them. Point is, many IDs look like numbers, but treating them as such can actually be misleading.

          Incidentally, thanks for the heads up on the flag. I've had a complaint about that before with regard to kicking out an epoch, which somebody did want to perform calculations on. In most cases, a number should be a number.

          • In that case, the API is wrong, because it expects an ID to be numeric, when it should be a string.

            Don't get me wrong, of course that flag to json_encode is useful, but I think it is a dirty solution, only needed when you can't fix it another way.

          • Spec always wins, of course. You're right. If the published API definition calls for an integer, provide one. I believe this is at the prototype stage, however -- when the spec is still subject to some flexibility.

  3. this is a tricky one, not sure i'd recommend that flag.

    the ideal solution is to cast the r-value when your schema defines the value as an int, allowing json_encode to guess type information could cause problems on the consumer side with type strict languages.

    imagine a name field with the value of 1000, this would be converted to an int when the consumer is expecting a string.

    echo json_encode( array( 'event_id' => (int)$event_id ) );

    cheers

    paul

  4. There have been some great comments on this thread already and it's making me think (which is always good!). I'm unsure if I should even be exposing IDs on this service, since they're only really internal references and the service provides hypermedia to get to related items.

    So it's back to the proverbial drawing board for now, while I think about the use cases and what data would be useful. I think the other numeric fields probably do want to be numbers, but as Paul says, there's the question about whether the automatic conversion is helpful.

  5. So why are you not just doing:

    echo json_encode(array('event_id' => 603));

    If its a int, don't quote it. If it is already quoted, then you doing something wrong before you are json encoding it.

  6. code:
    $arr = array('user_id'=>'163');
    $json=json_encode($arr,JSON_NUMERIC_CHECK);
    echo $json;

    I got the warning:
    Warning: json_encode() expects parameter 2 to be long

Leave a Reply

Please use [code] and [/code] around any source code you wish to share.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>