Strict RFC 6902 patching and deterministic diffs for PHP.
ALTO JSON Patch applies all six JSON Patch operations and generates stable patches between PHP values. Its identity-aware list diffing can express moves and nested changes instead of replacing complete lists, keeping generated patches compact and readable.
use Alto\JsonPatch\JsonPatch;
$before = ['status' => 'draft', 'tags' => ['php']];
$after = ['status' => 'published', 'tags' => ['php', 'json']];
$patch = JsonPatch::diff($before, $after);
$result = JsonPatch::apply($before, $patch);
assert($after === $result);The package has no runtime dependencies beyond PHP's JSON extension. Its test suite includes the RFC 6902 compliance corpus, and the codebase is analyzed at PHPStan level 10.
Install ALTO JSON Patch with Composer:
composer require alto/json-patchALTO JSON Patch requires PHP 8.3 or later and the JSON extension. The extension ships with PHP.
Apply a sequence of operations to an in-memory value:
use Alto\JsonPatch\JsonPatch;
$document = [
'user' => ['name' => 'Alice', 'role' => 'editor'],
'status' => 'draft',
];
$patch = [
['op' => 'replace', 'path' => '/user/role', 'value' => 'admin'],
['op' => 'replace', 'path' => '/status', 'value' => 'published'],
];
$result = JsonPatch::apply($document, $patch);The original value is unchanged. Operations run in order, and each operation sees the result of the preceding one.
JsonPatch::apply() supports every RFC 6902 operation:
| Operation | Effect |
|---|---|
add |
Insert or replace a value |
remove |
Delete an existing value |
replace |
Replace an existing value |
move |
Move a value to another path |
copy |
Copy a value to another path |
test |
Assert that a value matches |
Use JsonPatch::applyJson() to work directly with JSON strings. Read
Applying patches for path rules, validation, JSON handling, and failures.
Generate the operations needed to transform one state into another:
$patch = JsonPatch::diff(
['version' => 1, 'status' => 'draft'],
['version' => 2, 'status' => 'published'],
);Object keys are compared recursively. Lists use a longest common subsequence by default, producing
stable add and remove operations while preserving unchanged items.
Configure an identity key to express item moves and nested changes:
use Alto\JsonPatch\DiffOptions;
$options = new DiffOptions(
listIdentityByPointer: ['/items' => 'id'],
);
$patch = JsonPatch::diff($before, $after, $options);Read Generating patches for list strategies and their fallback behavior.
Patch paths follow RFC 6901. Use JsonPatch::get() and JsonPatch::test() to inspect values at a
path, or Pointer when another component needs to parse and compose paths.
$name = JsonPatch::get($document, '/user/name');
$isAdmin = JsonPatch::test($document, '/user/role', 'admin');Read JSON Pointers for root paths, list indices, and escaping. The complete guide also covers installation and a first end-to-end patch.
Contributions of all kinds are welcome. Visit the project on GitHub to report a bug, suggest a feature, or open a pull request.
Before submitting code, run:
# Runs PHP CS Fixer, PHPStan, and PHPUnit
composer qaChanges to public behavior should include tests and documentation.
ALTO JSON Patch is open source. You can support its continued development through GitHub Sponsors.
Sharing this package with others or starring it on GitHub is also much appreciated.
ALTO JSON Patch is released by ALTO PHP under the MIT License.