A PHP extension that wraps yyjson 0.12.0 behind a fastjson_* API mirroring ext/json. Side-by-side throughput, memory, and per-call latency against stock ext/json on a 21-file corpus, both hosted by PHP 8.4.22-dev.
vs ext/json, decode → stdClass (14.81 MB large corpus aggregate).
vs ext/json, encode a PHP value to JSON (14.81 MB large corpus aggregate).
vs ext/json, validate without building a tree (14.81 MB large corpus aggregate).
Decode to stdClass. fastjson's decode path is unchanged from yyjson's reader; assoc-array decode tracks it closely (see bench/baseline.md for the full assoc table).
| File | Size | ext/jsonMB/s | fastjsonMB/s | fastjson vsext/json |
|---|---|---|---|---|
| apache_builds.json | 124.3 KB | 367 | 980 | 2.67x |
| canada.json | 2.15 MB | 95 | 386 | 4.07x |
| citm_catalog.json | 1.65 MB | 446 | 1,065 | 2.39x |
| github_events.json | 63.6 KB | 413 | 1,260 | 3.05x |
| gsoc-2018.json | 3.17 MB | 335 | 1,044 | 3.11x |
| instruments.json | 215.2 KB | 345 | 918 | 2.66x |
| marine_ik.json | 2.85 MB | 180 | 297 | 1.65x |
| mesh.json | 706.6 KB | 188 | 483 | 2.57x |
| mesh.pretty.json | 1.50 MB | 242 | 654 | 2.70x |
| numbers.json | 146.6 KB | 225 | 919 | 4.09x |
| random.json | 498.5 KB | 246 | 465 | 1.89x |
| stringifiedphp.json | 139.9 KB | 338 | 2,487 | 7.36x |
| twitter.json | 616.7 KB | 393 | 942 | 2.40x |
| twitterescaped.json | 549.2 KB | 296 | 779 | 2.64x |
| update-center.json | 520.7 KB | 259 | 557 | 2.15x |
| aggregate | 14.81 MB | 209 | 542 | 2.59x |
| File | Size | ext/jsonMB/s | fastjsonMB/s | fast/callns | fastjson vsext/json |
|---|---|---|---|---|---|
| adversarial.json | 80 B | 168 | 315 | 242 ns | 1.87x |
| demo.json | 387 B | 308 | 728 | 507 ns | 2.36x |
| flatadversarial.json | 64 B | 131 | 246 | 248 ns | 1.88x |
| repeat.json | 11.1 KB | 434 | 884 | 12.3 µs | 2.04x |
| truenull.json | 11.7 KB | 208 | 845 | 13.5 µs | 4.07x |
| twitter_timeline.json | 41.2 KB | 306 | 869 | 46.4 µs | 2.84x |
| aggregate | 64.6 KB | 295 | 862 | — | 2.92x |
fastjson 0.3.0+ encodes with a one-stage direct-write encoder (zval → smart_str via yyjson's scalar writers, no intermediate mutable document), which is where the largest wins on float- and pretty-heavy inputs come from.
| File | Size | ext/jsonMB/s | fastjsonMB/s | fastjson vsext/json |
|---|---|---|---|---|
| apache_builds.json | 124.3 KB | 1,093 | 1,459 | 1.33x |
| canada.json | 2.15 MB | 56 | 671 | 12.07x |
| citm_catalog.json | 1.65 MB | 2,349 | 2,709 | 1.15x |
| github_events.json | 63.6 KB | 1,243 | 1,952 | 1.57x |
| gsoc-2018.json | 3.17 MB | 714 | 1,249 | 1.75x |
| instruments.json | 215.2 KB | 1,752 | 1,902 | 1.09x |
| marine_ik.json | 2.85 MB | 125 | 636 | 5.10x |
| mesh.json | 706.6 KB | 82 | 736 | 8.95x |
| mesh.pretty.json | 1.50 MB | 179 | 1,587 | 8.88x |
| numbers.json | 146.6 KB | 51 | 649 | 12.77x |
| random.json | 498.5 KB | 589 | 804 | 1.37x |
| stringifiedphp.json | 139.9 KB | 723 | 2,870 | 3.97x |
| twitter.json | 616.7 KB | 1,090 | 1,608 | 1.48x |
| twitterescaped.json | 549.2 KB | 981 | 1,412 | 1.44x |
| update-center.json | 520.7 KB | 778 | 992 | 1.28x |
| aggregate | 14.81 MB | 166 | 983 | 5.92x |
| File | Size | ext/jsonMB/s | fastjsonMB/s | fast/callns | fastjson vsext/json |
|---|---|---|---|---|---|
| adversarial.json | 80 B | 610 | 596 | 128 ns | 0.98x |
| demo.json | 387 B | 1,260 | 1,465 | 252 ns | 1.16x |
| flatadversarial.json | 64 B | 298 | 436 | 140 ns | 1.46x |
| repeat.json | 11.1 KB | 960 | 1,707 | 6.3 µs | 1.78x |
| truenull.json | 11.7 KB | 1,457 | 2,170 | 5.3 µs | 1.49x |
| twitter_timeline.json | 41.2 KB | 1,062 | 1,427 | 28.2 µs | 1.34x |
| aggregate | 64.6 KB | 1,093 | 1,563 | — | 1.43x |
fastjson's edge comes from vendor patch P-002 (YYJSON_READ_VALIDATE_ONLY), a no-tree validate entry point that drops peak memory ~2.7× vs the stock read path. ext/json validates by fully decoding and discarding.
| File | Size | ext/jsonMB/s | fastjsonMB/s | fastjson vsext/json |
|---|---|---|---|---|
| apache_builds.json | 124.3 KB | 414 | 2,470 | 5.97x |
| canada.json | 2.15 MB | 104 | 863 | 8.32x |
| citm_catalog.json | 1.65 MB | 551 | 2,457 | 4.46x |
| github_events.json | 63.6 KB | 476 | 2,877 | 6.04x |
| gsoc-2018.json | 3.17 MB | 353 | 1,469 | 4.16x |
| instruments.json | 215.2 KB | 437 | 2,142 | 4.90x |
| marine_ik.json | 2.85 MB | 238 | 821 | 3.45x |
| mesh.json | 706.6 KB | 212 | 1,155 | 5.45x |
| mesh.pretty.json | 1.50 MB | 259 | 1,575 | 6.09x |
| numbers.json | 146.6 KB | 237 | 1,347 | 5.68x |
| random.json | 498.5 KB | 333 | 1,409 | 4.23x |
| stringifiedphp.json | 139.9 KB | 334 | 2,699 | 8.07x |
| twitter.json | 616.7 KB | 502 | 2,431 | 4.84x |
| twitterescaped.json | 549.2 KB | 355 | 2,309 | 6.51x |
| update-center.json | 520.7 KB | 306 | 1,908 | 6.23x |
| aggregate | 14.81 MB | 241 | 1,260 | 5.23x |
| File | Size | ext/jsonMB/s | fastjsonMB/s | fast/callns | fastjson vsext/json |
|---|---|---|---|---|---|
| adversarial.json | 80 B | 160 | 652 | 117 ns | 4.09x |
| demo.json | 387 B | 360 | 1,425 | 259 ns | 3.96x |
| flatadversarial.json | 64 B | 161 | 555 | 110 ns | 3.45x |
| repeat.json | 11.1 KB | 536 | 1,987 | 5.5 µs | 3.70x |
| truenull.json | 11.7 KB | 232 | 2,314 | 4.9 µs | 9.97x |
| twitter_timeline.json | 41.2 KB | 382 | 2,688 | 15.0 µs | 7.04x |
| aggregate | 64.6 KB | 357 | 2,438 | — | 6.84x |
Single-call peak heap, fastjson / ext-json. Above 1.0 means fastjson uses more — the price of yyjson's build-a-doc-then-walk model on decode. Encode is at parity (direct-write, no mutable doc); validate trades memory for the no-tree fast path.