PHPackages                             alto/json-patch - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Parsing &amp; Serialization](/categories/parsing)
4. /
5. alto/json-patch

ActiveLibrary[Parsing &amp; Serialization](/categories/parsing)

alto/json-patch
===============

A PHP JSON-Patch library based on RFC 6902 for generating smart diffs, applying patches, and rebuilding data structures.

v1.0.0(5mo ago)23MITPHPPHP ^8.3CI passing

Since Jan 17Pushed 5mo agoCompare

[ Source](https://github.com/PhpAlto/json-patch)[ Packagist](https://packagist.org/packages/alto/json-patch)[ Docs](https://github.com/phpalto/json-patch)[ GitHub Sponsors](https://github.com/sponsors/smnandre)[ RSS](/packages/alto-json-patch/feed)WikiDiscussions main Synced today

READMEChangelog (1)Dependencies (3)Versions (2)Used By (0)

ALTO \\ JSON Patch
==================

[](#alto--json-patch)

A strict, auditable [JSON Patch](https://en.wikipedia.org/wiki/JSON_Patch) implementation for PHP 8.3+. This library handles two concerns with precision:

1. **Apply**: A deterministic **[RFC 6902](https://datatracker.ietf.org/doc/html/rfc6902)** engine that replays patches exactly.
2. **Diff**: A smart diff generator that produces stable, readable patches.

Built for systems where change history matters.

---

 [![PHP Version](https://camo.githubusercontent.com/c0b28ee3b309c38fa5ad32ec2ae9a6f82a8d50e397048bfec11bfdf85dfafba2/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e332b2d6666656664663f6c6f676f436f6c6f723d7768697465266c6162656c436f6c6f723d303030)](https://github.com/PhpAlto/json-patch) [![CI](https://camo.githubusercontent.com/2c678dbd40c33085024d72e4935719336204f89200bd5c79eb6420541001ed17/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f506870416c746f2f6a736f6e2d70617463682f43492e796d6c3f6272616e63683d6d61696e266c6162656c3d5465737473266c6f676f436f6c6f723d7768697465266c6f676f53697a653d6175746f266c6162656c436f6c6f723d30303026636f6c6f723d666665666466)](https://github.com/PhpAlto/json-patch/actions) [![Packagist Version](https://camo.githubusercontent.com/2de8758d7ac954d181cb7004580e0af0065deefbbc4c7f6696f8f8caf472ba0e/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f616c746f2f6a736f6e2d70617463683f6c6162656c3d537461626c65266c6f676f436f6c6f723d7768697465266c6f676f53697a653d6175746f266c6162656c436f6c6f723d30303026636f6c6f723d666665666466)](https://packagist.org/packages/alto/json-patch) [![PHP Version](https://camo.githubusercontent.com/79820ea4fbf7ba81b487f71ba6cd7cc3990b572b950544e8be10876f72a81ba7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f504850556e69742d3130302532352d6666656664663f6c6f676f436f6c6f723d7768697465266c6162656c436f6c6f723d303030)](https://github.com/PhpAlto/json-patch) [![PHP Version](https://camo.githubusercontent.com/46cab1ca7fbef6e1ecb3fcb46ebda03c929e31a141d14b601a9ecbfc868873d5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048505374616e2d4c564c25323031302d6666656664663f6c6f676f436f6c6f723d7768697465266c6162656c436f6c6f723d303030)](https://github.com/PhpAlto/json-patch) [![License](https://camo.githubusercontent.com/86d6046776bda70bd10b7c0e99d67b04227be1b05c261aa78331a192612559a8/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f506870416c746f2f6a736f6e2d70617463683f6c6162656c3d4c6963656e7365266c6f676f436f6c6f723d7768697465266c6f676f53697a653d6175746f266c6162656c436f6c6f723d30303026636f6c6f723d666665666466)](./LICENSE)

- **Pure PHP**: Tiny surface area, no heavy dependencies.
- **Strict Types**: Built for PHP 8.3+ with strict typing.
- **Deterministic**: Error model designed for auditability.
- **Smart Diffing**: Supports standard list replacement or smart "by-id" list diffing for readable patches.

Installation
------------

[](#installation)

```
composer require alto/json-patch
```

Why Alto JSON Patch?
--------------------

[](#why-alto-json-patch)

**For audit logs**: Deterministic apply means you can verify patch integrity. Store the parent hash, the patch, and the result hash. Replaying the patch will always produce the same result.

**For readable diffs**: Generate clean patches that humans can review. Optional identity-based list diffing produces granular operations instead of replacing entire arrays.

**For reliability**: Pure PHP with strict types. No magic, no surprises.

Quick Start
-----------

[](#quick-start)

```
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);
// ['user' => ['name' => 'Alice', 'role' => 'admin'], 'status' => 'published']
```

Generate Patches
----------------

[](#generate-patches)

Create patches automatically by diffing two states:

```
$before = ['version' => 1, 'status' => 'draft'];
$after = ['version' => 2, 'status' => 'published', 'author' => 'Alice'];

$patch = JsonPatch::diff($before, $after);
// [
//     ['op' => 'replace', 'path' => '/version', 'value' => 2],
//     ['op' => 'replace', 'path' => '/status', 'value' => 'published'],
//     ['op' => 'add', 'path' => '/author', 'value' => 'Alice'],
// ]
```

Smart List Diffing
------------------

[](#smart-list-diffing)

By default, lists are replaced entirely when they differ. For granular control, use identity-based diffing:

```
use Alto\JsonPatch\DiffOptions;

$before = [
    'items' => [
        ['id' => 'a', 'qty' => 1],
        ['id' => 'b', 'qty' => 2],
    ],
];

$after = [
    'items' => [
        ['id' => 'b', 'qty' => 3],  // Modified and reordered
        ['id' => 'c', 'qty' => 1],  // Added
    ],
];

$options = new DiffOptions(['/items' => 'id']);
$patch = JsonPatch::diff($before, $after, $options);
// Generates move, add, remove, and replace operations for individual items
```

This produces readable patches where reviewers can see exactly which items changed.

Utility Methods
---------------

[](#utility-methods)

```
// Get a value at a JSON pointer path
$name = JsonPatch::get($document, '/user/name');

// Test if a value matches (returns bool)
$isAdmin = JsonPatch::test($document, '/user/role', 'admin');

// Validate patch structure without applying
$errors = JsonPatch::validate($patch);
```

Audit Trail Example
-------------------

[](#audit-trail-example)

```
class ChangeLog
{
    public function recordChange(array $before, array $after): void
    {
        $patch = JsonPatch::diff($before, $after);

        $this->store([
            'parent_hash' => hash('sha256', json_encode($before)),
            'patch' => $patch,
            'result_hash' => hash('sha256', json_encode($after)),
            'timestamp' => time(),
        ]);
    }

    public function verifyIntegrity(string $recordId): bool
    {
        $record = $this->fetch($recordId);
        $parent = $this->reconstructState($record['parent_hash']);

        $result = JsonPatch::apply($parent, $record['patch']);
        $computedHash = hash('sha256', json_encode($result));

        return $computedHash === $record['result_hash'];
    }
}
```

Supported Operations
--------------------

[](#supported-operations)

All RFC 6902 operations:

- `add`: Add a value at a path
- `remove`: Remove a value at a path
- `replace`: Replace a value at a path
- `move`: Move a value from one path to another
- `copy`: Copy a value from one path to another
- `test`: Assert a value matches (useful for conditional patches)

Error Handling
--------------

[](#error-handling)

Operations throw `JsonPatchException` with clear messages:

```
try {
    JsonPatch::apply($doc, $patch);
} catch (JsonPatchException $e) {
    // "Operation 0 (replace): path '/missing/path' not found."
    // "Operation 1 (add): invalid path '/items/-1'."
}
```

Advanced Usage
--------------

[](#advanced-usage)

### Float Comparison

[](#float-comparison)

`JsonPatch` uses strict equality (`===`) for values. Be aware that `json_decode` may treat numbers differently depending on flags. For example, `1.0` (float) is not strictly equal to `1` (int). Ensure your input documents use consistent types if strict equality is required.

Limitations
-----------

[](#limitations)

### `applyJson`: Empty Object vs Array

[](#applyjson-empty-object-vs-array)

When using `JsonPatch::applyJson()`, the underlying `json_decode` converts empty JSON objects `{}` into empty PHP arrays `[]`. Since PHP does not distinguish between empty associative arrays (objects) and empty indexed arrays (lists), an input of `{"key": {}}` may result in `{"key": []}` after a round-trip. If strictly preserving `{}` vs `[]` is critical, consider using `apply()` with pre-decoded structures where you can control the object mapping (e.g. `json_decode($json, false)` for `stdClass`).

API Reference
-------------

[](#api-reference)

### `JsonPatch`

[](#jsonpatch)

MethodDescription`apply(array $doc, array $patch): array`Apply a patch to a document`applyJson(string $docJson, string $patchJson, int $flags = 0): string`Apply patch to JSON string`diff(array $from, array $to, ?DiffOptions $opts = null): array`Generate patch from two states`get(array $doc, string $path): mixed`Get value at JSON pointer path`test(array $doc, string $path, mixed $value): bool`Test if value matches at path`validate(array $patch): array`Validate patch structure, returns errors### `DiffOptions`

[](#diffoptions)

Configure identity-based list diffing:

```
$options = new DiffOptions([
    '/users' => 'id',        // Use 'id' field for /users array
    '/items' => 'sku',       // Use 'sku' field for /items array
]);
```

License
-------

[](#license)

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

```

```

###  Health Score

35

—

LowBetter than 77% of packages

Maintenance70

Regular maintenance activity

Popularity6

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity50

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

168d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/a8951d49b371d210280a58ce48969a07d1f49924810f8a1fab3a9343eb46fdc9?d=identicon)[simonandre](/maintainers/simonandre)

---

Top Contributors

[![smnandre](https://avatars.githubusercontent.com/u/1359581?v=4)](https://github.com/smnandre "smnandre (1 commits)")

---

Tags

diffjson-diffjson-patchpatchpatch-diffphp-diffrfc6902smart-diffjsondiffstateversioningAuditdeterministicpatchchange-trackingRFC6902json-diff

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/alto-json-patch/health.svg)

```
[![Health](https://phpackages.com/badges/alto-json-patch/health.svg)](https://phpackages.com/packages/alto-json-patch)
```

###  Alternatives

[justinrainbow/json-schema

A library to validate a json schema.

3.6k334.7M789](/packages/justinrainbow-json-schema)[mtdowling/jmespath.php

Declaratively specify how to extract elements from a JSON document

2.0k504.8M167](/packages/mtdowling-jmespathphp)[jms/serializer

Library for (de-)serializing data of any complexity; supports XML, and JSON.

2.3k141.9M929](/packages/jms-serializer)[jms/serializer-bundle

Allows you to easily serialize, and deserialize data of any complexity

1.8k92.4M679](/packages/jms-serializer-bundle)[colinodell/json5

UTF-8 compatible JSON5 parser for PHP

30525.1M56](/packages/colinodell-json5)[clue/ndjson-react

Streaming newline-delimited JSON (NDJSON) parser and encoder for ReactPHP.

15882.2M31](/packages/clue-ndjson-react)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
