psx/json
A lightweight PHP library for parsing and writing JSON. psx/json provides a simple, dependable API for converting between JSON strings and PHP values, making it useful for APIs, configuration files, and data exchange in PSX-based or standalone projects.
Architecture fit
psx/json is a Composer-installable, PSR-4, framework-agnostic library implementing JSON-Pointer (RFC 6901) and JSON-Patch (RFC 6902) primitives over decoded PHP documents. It is a leaf utility, not an HTTP, ORM, or container component, so it slots under Laravel without fighting the framework.JsonPatchService contract bound in a small JsonServiceProvider, with PSX classes confined to the adapter layer.application/json-patch+json and merge-patch PATCH endpoints, delta storage for audit/event-sourced records, multi-tenant config layering (base document + tenant patches), webhook payload reshaping, and ruleset/feature-flag document mutation.Integration feasibility
composer require psx/json). The real cost is containment, test coverage, and an exit path.psx/data, PSR-7/PSR-17 abstractions). If those arrive with you, you inherit version constraints that can collide with Laravel's own PSR pins.Technical risk
~0/~1, - array append, test op atomicity, move/copy aliasing). These are library-agnostic, but a low-traffic library gets fewer bug reports against them.php constraint against your Laravel/PHP baseline before the spike, not after.Key questions
composer why-level dependency tree, and does it constrain PHP, PSR, or PHPUnit versions relative to Laravel 10/11?test operation, or can it leave a partially mutated document? This determines whether we can trust it for writes.swaggest/json-diff (patch + pointer + merge-patch, actively maintained) as the default alternative? The decision should be "PSX wins on X," not "PSX was first in the search results."Stack fit
JsonPatchApplier interface, one PSX-backed implementation, one binding. Everything else in the codebase depends on the interface.JSON_THROW_ON_ERROR, reject non-object/array roots for patch targets, and return a domain result object rather than raw arrays or PSX exceptions.Content-Type, array of operations, op allowlist) so malformed patches fail at the edge rather than deep in the applier.Migration path
NullJsonPatchApplier/array-diff fallback implementation behind the same contract. Feature-flag selection via config. This is the exit ramp and it is cheap now, expensive later.PUT/PATCH handlers in this phase.array_merge/recursive-replace logic. Those are load-bearing and often encode undocumented business rules that JSON-Patch semantics will not reproduce.Compatibility
php constraint vs. your Laravel baseline (Laravel 10 → PHP 8.1+, Laravel 11 → 8.2+). If the package trails, pin and schedule the upgrade separately from the framework upgrade.composer require --dry-run first and read the resolution output for PSR/PHPUnit downgrades. A test-tooling downgrade is a hidden tax on the whole repo.Sequencing
swaggest/json-diff on your real payload sizes; revisit the build-vs-buy call before broadening adoption.Maintenance
composer audit and composer outdated review, and a documented policy that the vendored fork is refreshed at least annually. Pin exactly (composer.lock) and never allow floating constraints on this package.Support
Scaling
Failure modes
test op mid-patch could leave a half-mutated document. Confirm the library aborts cleanly; if not, apply to a deep copy and swap on success. This is the highest-severity failure mode because it silently corrupts writes.{"0": ...} can silently hit array index 0. This is a data-integrity bug, not a crash, and it is the one most likely to reach production.~ and / in keys produce not-found errors that surface as 400s to customers. Centralize pointer encoding and test it.int range lose precision through decode/encode. Financial and ID fields need string encoding at the boundary.Ramp-up
replace vs add and from array index assumptions.Verdict
Low integration cost, credible technical fit, and a genuinely valuable capability (delta storage, standards-compliant PATCH) against a weak adoption and maintenance signal. The package is defensible only behind a thin internal interface with a tested fallback and a fork plan. Approve for a bounded spike on one low-traffic surface; make the broader commitment contingent on the conformance results and a head-to-head against swaggest/json-diff on your own payloads.
How can I help you explore Laravel packages today?