hoa/json
Hoa\Json is a PHP library for parsing, encoding, and manipulating JSON documents. It provides a grammar-based parser and structured tools for working with JSON data reliably in PHP applications.
Install and immediately smoke-test. composer require hoa/json pulls the last tag from 2017-01-13 plus its Hoa dependency chain (hoa/consistency, hoa/exception, hoa/stream, hoa/protocol, hoa/visitor). Because the package is archived, treat installation as a compatibility experiment, not a routine require: run one parse/dump in a scratch script on the exact PHP version your Laravel app uses (8.1+ for Laravel 10/11) before letting it near composer.json. If you see deprecation noise or fatal errors from the Hoa bootstrap, stop — there will be no upstream fix.
Read the source, not the docs. The repo is tiny. Order: README.md → src/Json.php (entry point) → src/Structure.php (the parsed node tree) → src/Visitor/ (all the behavior you'll actually reuse). The Hoa docs site is archived alongside it and is frequently older than the tag you install, so verify method names against src/.
Minimal first use — parse, then visit. The package's whole value proposition is that parsing yields a traversable structure you can hand to a visitor, rather than an anonymous stdClass/array from json_decode:
use Hoa\Json\Json;
use Hoa\Json\Visitor\Dump;
$structure = Json::parse('{"user":{"name":"Ada","roles":["admin"]}}'); // confirm signature in src/Json.php
$structure->accept(new Dump()); // renders an indented tree with types
php artisan json:inspect payload.json) or a tinker session that dumps a messy webhook/API payload as a typed tree, which is far easier to eyeball than json_decode($s) + print_r. If your need is "get an array out of JSON," close the tab and use json_decode.App\Support\JsonInspector) that accepts a string and returns either the Hoa structure or your own DTO. Controllers, jobs, and commands depend on that service, never on Hoa\Json\Json directly — this is your migration seam when the package is finally removed.Dump) and override the node callback to accumulate a path stack, so you can report user.roles[0] = "admin" style locations. This is the one thing the package gives you that json_decode + a hand-rolled recursive walk does not give you for free.password|token|secret and re-emits (or just records paths) is a legitimate use in queue jobs that log third-party payloads. Keep the redaction visitor stateless and instantiate it per document.tests/Fixtures/json/ and assert on visitor output (path/type pairs) rather than on Dump strings; dump output is a human format and will churn.ext/json. Reserve it for commands, tests, debugging middleware, and offline jobs — never per-request parsing of large bodies.$response->body(), run it through the parser, and dump the tree on assertion failure. That gives you typed structure instead of a wall of JSON.\JsonException. Hoa's exception classes extend the project's own exception base and use sprintf-style constructors; catching \JsonException around a parse will not work. Catch the Hoa type at the boundary and rethrow as RuntimeException/ValidationException so Laravel's handler and your logs behave normally.hoa/protocol installs a stream wrapper layer. It's global state. If you already use custom stream wrappers, or tools that manipulate include_path, test for interference; prefer parsing from strings rather than Hoa streams to avoid touching it at all.Dump is not round-trippable. Do not use the dump visitor to produce output you intend to feed back into an API — it renders a tree, not JSON. Re-serialize with json_encode on your own data.justinrainbow/json-schema; if it's extraction, symfony/property-access or plain json_decode($s, true, 512, JSON_THROW_ON_ERROR) plus a recursive walker will cover you with far less risk.json_decode with JSON_THROW_ON_ERROR, a recursive walker that carries a path, and Symfony\Component\VarDumper for pretty output. Write the wrapper interface first so swapping is a one-file change.How can I help you explore Laravel packages today?