This documentation covers the FastJsonPatch
PHP class, designed to apply a series of JSON Patch operations as specified in RFC 6902.
Fast JSON Patch is the fastest fully RFC compliant package available in PHP, you can find compliance test and benchmark results here.
composer require blancks/fast-jsonpatch-php
The FastJsonPatch
class provides a way to modify JSON documents using a structured patch object.
The patch object contains an array of operations (add
, remove
, replace
, move
, copy
, and test
) that describe the changes to be made to the target JSON document.
Below is an example of how to use the FastJsonPatch
class to apply a patch to a JSON document:
use blancks\JsonPatch\FastJsonPatch;
use blancks\JsonPatch\exceptions\FastJsonPatchException;
$document = '{
"contacts":[
{"name":"John","number":"-"},
{"name":"Dave","number":"+1 222 333 4444"}
]
}';
$patch = '[
{"op":"add","path":"/contacts/-","value":{"name":"Jane", "number":"+1 353 644 2121"}},
{"op":"replace","path":"/contacts/0/number","value":"+1 212 555 1212"},
{"op":"remove","path":"/contacts/1"}
]';
$FastJsonPatch = FastJsonPatch::fromJson($document);
try {
$FastJsonPatch->apply($patch);
} catch (FastJsonPatchException $e) {
// here if patch cannot be applied for some reason
echo $e->getMessage(), "\n";
}
var_dump($FastJsonPatch->getDocument());
Expected Output:
object(stdClass) (1) {
["contacts"]=>
array(2) {
[0]=>
object(stdClass) (2) {
["name"]=>
string(4) "John"
["number"]=>
string(15) "+1 212 555 1212"
}
[1]=>
object(stdClass) (2) {
["name"]=>
string(4) "Jane"
["number"]=>
string(15) "+1 353 644 2121"
}
}
}
The expected workflow is that once you got a FastJsonPatch
instance you can call the apply
method each time a new patch is received and this is particularly handy in long-running context like a websocket client/server.
Patch application is designed to be atomic. If any operation of a given patch fails the original document is restored, ensuring a consistent state of the document.
__construct(mixed &$document, ?JsonHandlerInterface $JsonHandler = null, ?JsonPointerHandlerInterface $JsonPointerHandler = null)
- Description: Initializes a new instance of the
FastJsonPatch
class. - Parameters:
mixed &$document
: The decoded JSON document.?JsonHandlerInterface $JsonHandler
: An instance of the JSON handler which will be responsible for encoding/decoding and CRUD operations.
The default handler isblancks\JsonPatch\json\handlers\BasicJsonHandler
and decodes json objects as php \stdClass instances. This is the recommended way.
If you application requires working with associative arrays only, you can pass ablancks\JsonPatch\json\handlers\ArrayJsonHandler
instance instead.?JsonPointerHandlerInterface $JsonPointerHandler
: Instance of the object responsible to validate and parse JSON Pointers.
The default handler isblancks\JsonPatch\json\pointer\JsonPointer6901
- Returns: Instance of the
FastJsonPatch
class. - Example:
$document = ['one', 'two', 'three']; $FastJsonPatch = new FastJsonPatch($document);
static function fromJson(string $patch, ?JsonHandlerInterface $JsonHandler = null, ?JsonPointerHandlerInterface $JsonPointerHandler = null) : void
- Description: Returns a new instance of the
FastJsonPatch
class. - Parameters:
string $document
: A json encoded document to which the patches will be applied?JsonHandlerInterface $JsonHandler
: An instance of the JSON handler which will be responsible for encoding/decoding and CRUD operations.
The default handler isblancks\JsonPatch\json\handlers\BasicJsonHandler
and decodes json objects as php \stdClass instances. This is the recommended way.
If you application requires working with associative arrays only, you can pass ablancks\JsonPatch\json\handlers\ArrayJsonHandler
instance instead.?JsonPointerHandlerInterface $JsonPointerHandler
: Instance of the object responsible to validate and parse JSON Pointers.
The default handler isblancks\JsonPatch\json\pointer\JsonPointer6901
- Example:
$FastJsonPatch = FastJsonPatch::fromJson('{"foo":"bar","baz":["qux","quux"]}');
- Description: Applies a series of patch operations to the specified JSON document. Ensures atomicity by applying all operations successfully or restoring the original document if any operation fails.
- Parameters:
string $patch
: A json-encoded array of patch operations.
- Exceptions:
- Throws
FastJsonPatchValidationException
if a patch operation is invalid or improperly formatted. - Throws
FastJsonPatchException
if any other error occurs while applying the patch
- Throws
- Example:
$patch = '[{"op":"test", "path":"/foo", "value":"bar"}]'; $FastJsonPatch->apply($patch);
- Description: Tells if the $patch is syntactically valid
- Parameters:
string $patch
: A json-encoded array of patch operations.
- Returns: True is the patch is valid, false otherwise
- Example:
$patch = '[{"op":"add","path":"/foo"}]'; // invalid because there's no "value" key if ($FastJsonPatch->isValidPatch($patch)) { $FastJsonPatch->apply($patch); } else { echo "Invalid patch!"; }
- Description: Uses a JSON Pointer (RFC-6901) to fetch data from the referenced document
- Parameters:
string $patch
: A json pointer
- Returns: The value located by the provided pointer
- Example:
$FastJsonPatch = FastJsonPatch::fromJson('{"foo":"bar","baz":["qux","quux"]}'); echo $FastJsonPatch->read('/baz/1'); // "quux"
- Description: Returns the document reference that the instance is holding
- Returns: The referenced document
- Example:
$FastJsonPatch = FastJsonPatch::fromJson('["qux","quux"]'); var_dump($FastJsonPatch->getDocument()); // array(2) {[0]=> string(3) "qux" [1]=> string(4) "quux"}
- Description: Allows to register new patch operation handlers or to override existing ones.
- Parameters:
PatchOperationInterface $PatchOperation
: The handler class for handling the operation.
- Example:
$FastJsonPatch->registerOperation(new Add);
- Description: Adds a value to the specified path in the document.
- Parameters:
path
: JSON Pointer to the location where the value should be added.value
: The value to add.
- Example:
{"op":"add","path":"/new/key","value":"example"}
- Description: Removes the value at the specified path.
- Parameters:
path
: JSON Pointer to the location of the value to remove.
- Example:
{"op":"remove","path":"/old/key"}
- Description: Replaces the value at the specified path with a new value.
- Parameters:
path
: JSON Pointer to the location of the value to replace.value
: The new value.
- Example:
{"op":"replace","path":"/replace/key","value":"newValue"}
- Description: Moves the value from one path to another.
- Parameters:
from
: JSON Pointer to the source location of the value to move.path
: JSON Pointer to the destination location.
- Example:
{"op":"move","from":"/old/key","path":"/new/key"}
- Description: Copies the value from one path to another.
- Parameters:
from
: JSON Pointer to the source location of the value to copy.path
: JSON Pointer to the destination location.
- Example:
{"op":"copy","from":"/source/key","path":"/target/key"}
- Description: Tests that the specified value matches the value at the path.
- Parameters:
path
: JSON Pointer to the location of the value to test.value
: The value to compare.
- Example:
{"op":"test","path":"/test/key","value":"expectedValue"}
composer test
Test cases comes from json-patch/json-patch-tests and extended furthermore to ensure a strict compliance with RFC-6902.
Contributions are welcome! 🎉
Feel free to fork the repository if you'd like to contribute to this project!
Please ensure your contributions align with the project's goals and code style:
- Use
composer run static-analyse
for static analysis - Use
composer run pretty-php
to reformat your code before commit - Provide unit tests for the code you wrote, this project targets 100% coverage
- It is ok to write alternative handlers to address slower operations, such as working with huge json files
- Any changes that hurts the package performance in its default configuration must be motivated with a good reason
If you have any questions, need guidance, reporting a bug or suggesting an improvement feel free to open an issue. Every bit helps!
Thank you for helping to improve this project!
This software is licensed under the MIT License.