php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #75400 Already As JSON
Submitted: 2017-10-17 19:55 UTC Modified: 2021-04-22 14:04 UTC
Votes:5
Avg. Score:3.6 ± 0.8
Reproduced:2 of 3 (66.7%)
Same Version:1 (50.0%)
Same OS:1 (50.0%)
From: jwalton at aretehs dot com Assigned:
Status: Suspended Package: JSON related
PHP Version: 7.0.24 OS: Any
Private report: No CVE-ID: None
Have you experienced this issue?
Rate the importance of this bug to you:

 [2017-10-17 19:55 UTC] jwalton at aretehs dot com
Description:
------------
Ability for an object to specify that it already is encoded.

Example, data returned from a database may already be in JSON format, so it seems pretty pointless to decode it, only to re-encode it in another object.

It could be as simple as adding a new function maybe, like, jsonRawSerialize() or something.

My issue is that sometimes the the json is over 200k and it adds quite a bit of extra CPU cycles.

Test script:
---------------
// Example

class MyJSON {
  public function jsonSerialize() {
    return '{"myobject":true}';
  }
}

print json_encode((object)[
  "result" => new MyJSON()
]);

// should print
//    {"result"=>{"myobject"=>true}}
//
//right now you have to do

class MyJSON2 {
  public function jsonSerialize() {
    return json_decode('{"myobject":true}');
  }
}

print json_encode((object)[
  "result" => new MyJSON2()
]);



Patches

jsonrawserializable (last revision 2017-10-25 01:14 UTC by jwalton at aretehs dot com)

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2017-10-23 23:57 UTC] pollita@php.net
-Status: Open +Status: Analyzed
 [2017-10-23 23:57 UTC] pollita@php.net
That's not unreasonable.  I'll propose it to the list and see about getting it into 7.3.
 [2017-10-24 08:45 UTC] kelunik@php.net
-Assigned To: +Assigned To: pollita
 [2017-10-24 08:45 UTC] kelunik@php.net
Assigning to you, pollita, because you plan to work on it.
 [2017-10-24 23:26 UTC] jwalton at aretehs dot com
Created a performance script.

php t.php

json_decenc = 53.06218791008
json_enc    = 18.900541067123
json_str    = 0.18521690368652

function json_decenc() {
  global $jsondata;
  $data = json_encode((object)[
    "result" => json_decode($jsondata)
  ]);
}

function json_enc() {
  global $jd;
  $data = json_encode((object)[
    "result" => $jd
  ]);
}

function json_str() {
  global $jsondata;
  $data = '{"result":'.$jsondata.'}';
}

json document is 278,567 bytes(276k) long.

json_decenc (does a decode and encode of that data into a new json document)
json_enc (only does an encode of already decoded data)  This shows that 64% of the time is spent decoding the data as encoding that data is relatively fast.
json_str is basically string appending, this is the fastest method but doesn't maintain json integrity.

As for the messages in internal, I understand where they are coming from but they are assuming that people will be building these string. And while they CAN, the main draw to this is that it could be coming from a database like PostgreSQL which already maintains the integrity of the json (JSON data type can't be inserted invalidly)
 [2017-10-25 00:45 UTC] jwalton at aretehs dot com
So, surprisingly, unlike other PHP code (that I wouldn't touch with a 10 foot pole) the ext/json was surprisingly clean.  I was able to add this functionality in myself in 15 mins.  Tested it on one of my website and wow, what an increase in performance.

Added JsonRawSerialize but I changed the function name to jsonSerialized (past tense).

Same performance script (but done on a different machine)

<?php

$jsondata = file_get_contents("test.json");
$jd = json_decode($jsondata);

class Test implements JsonRawSerializable {
  public $str;
  function __construct(&$str) {
    $this->str = $str;
  }
  function jsonSerialized() {
    return $this->str;
  }
}

$jrs = new Test($jsondata);

function timing($func, $iter) {
  $stime = microtime(true);
  for($counter=1;$counter<$iter;$counter++) {
    $func();
  }
  $etime = microtime(true);
  return $etime - $stime;
}

function json_decenc() {
  global $jsondata;
  $data = json_encode((object)[
    "result" => json_decode($jsondata)
  ]);
}

function json_enc() {
  global $jd;
  $data = json_encode((object)[
    "result" => $jd
  ]);
}

function json_str() {
  global $jsondata;
  $data = '{"result":'.$jsondata.'}';
}

function json_raw() {
  global $jrs;
  $data = json_encode([
    "result" => $jrs
  ]);
}

print "json_decenc = ".timing('json_decenc', 10000)."\n";
print "json_enc    = ".timing('json_enc', 10000)."\n";
print "json_str    = ".timing('json_str', 10000)."\n";
print "json_raw    = ".timing('json_raw', 10000)."\n";

gave me
json_decenc = 35.672137975693
json_enc    = 14.386140823364
json_str    = 0.11590504646301
json_raw    = 0.35667610168457

only ~twice as slow as string concat, 99 times faster than decode(encode()), and its even faster than just re-encoding the same object.

Unfortunately, the pure php json decoder/encoder doesn't hold a candle to the C one.  To bad its not built in.

All I did was check the return value Z_TYPE() == IS_STRING and then pass that directly to the smart_str_appendl() (saw that it was used for smart_str_appendl(buf, "true", 4); -> smart_str_appendl(buf, Z_STRVAL(retval), Z_STRLEN(retval));

I have a patch if anyone is interested.
 [2017-10-25 14:37 UTC] pollita@php.net
As you've seen, the pushback is pretty strong atm, would you mind presenting your case on internals directly?
 [2017-10-26 02:34 UTC] jwalton at aretehs dot com
I would, but I don't have permissions to put anything in that mail list.
 [2017-10-26 08:56 UTC] spam2 at rhsoft dot net
which permissions? it's just a mailing list like any other where you can subscribe
 [2017-11-06 21:24 UTC] jwalton at aretehs dot com
Because sending messages to the mailing list get rejected. And there is no way to register or sign up to get access.  And before you point me to the main mailing list page, the subscribe/unsubscribe buttons do not do anything.  I've put in 4 different email addresses across 3 providers, and 2 weeks later, still no confirmation emails.
 [2021-04-22 11:31 UTC] cmb@php.net
-Status: Analyzed +Status: Suspended
 [2021-04-22 11:31 UTC] cmb@php.net
Hmm, seems this has stalled, and according to the discussion would
need an RFC.  If anybody is still interested in this feature,
please pursue the RFC process[1].  For the time being, I suspend
this ticket.

> Because sending messages to the mailing list get rejected.

I don't know whether the subscription form is still broken, but
you can manually subscribe by sending a mail to

     mailinglist-subscribe@example.org

See the EZML docs[2] for further details.

[1] <https://wiki.php.net/rfc/howto>
[2] <http://untroubled.org/ezmlm/ezman/ezman1.html#ss1.2>
 [2021-04-22 14:04 UTC] pollita@php.net
-Assigned To: pollita +Assigned To:
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Tue Mar 19 10:01:30 2024 UTC