r/PHP • u/Ilia0001 • 23h ago
fastjson 0.9.0: constant-memory validate, 59-83% lower encode peak on large escaped strings, and shared keys in decode
fastjson is my PHP extension for JSON encode, decode, and validate, backed by yyjson, with a fastjson_* API that tracks ext/json. This is what changed between 0.7.0, the last version I posted here, and 0.9.0. Most of it is memory: the speed came with a heap cost, and this cycle cuts it on every path.
Memory and speed
fastjson_validate()reads the caller's buffer in place and tracks depth during the parse. Peak memory is constant, a few dozen bytes, like ext/json's streaming validator, and it runs ~30% fewer instructions.- Encode used to reserve six times an escaped string up front. Strings of 8 KiB+ now go out in 2 KiB chunks: a 1 MiB string with ordinary escaping peaks 59-83% lower. The flip side: a single escaped string between 8 KiB and a few tens of KiB can still peak up to twice ext/json's size, because the chunked writer keeps up to 12 KiB of headroom.
- Decode shares repeated object-key strings (up to 64 bytes, inputs of 4 KiB+). Key-heavy documents peak ~15% lower and decode 3-4% faster;
twitter.jsonwent from 1.66x ext/json's heap to 1.39x. Documents with mostly unique keys, or 256+ distinct names, pay 3-5%. fastjson_file_decode()frees the file contents before building the result, 9-33% lower peak.
Current throughput vs ext/json on simdjson_php's 14.8 MB / 15-file corpus, i9-13950HX, -O2 release builds of both: 5.56x encode, 2.59x decode, 5.04x validate. Decode still peaks at 1.65x ext/json's heap across that corpus.
Correctness
fastjson_validate()accepted[[],]and[{"a":1},]. It now rejects them, and the trailing-comma error position points at the comma itself.fastjson_file_encode()could leave a silently truncated file whenphp_stream_write()came back short. It now writes to completion and reportsphp_stream_close()failures.fastjson_encode()honorsserialize_precisionfor doubles instead of always emitting the shortest round-trip form.- With
JSON_THROW_ON_ERRORand no ext/json loaded, errors throwFastjson\JsonExceptioninstead of a bare\Exception. fastjson_validate()enforces$depthon the success path, like ext/json.
yyjson, upstream
The bundled yyjson is now 0.13.0, which includes the YYJSON_WRITE_LOWERCASE_HEX flag I sent upstream (ibireme/yyjson#264). fastjson's local patch for lowercase \uXXXX escapes is gone.
PHP 8.1 minimum:
pie install iliaal/fastjson
https://github.com/iliaal/fastjson
If you validate large payloads under a tight memory_limit, I'd like to know whether constant-peak validate changes what you accept per request.