The most compliant PHP implementation of JSON Logic. ✨
shiny/json-logic-php is a pure PHP, zero-dependency JSON Logic implementation — the only PHP library that passes 100% of the official JSON Logic tests (in stdclass mode), with no external dependencies and PHP 8.1+ compatibility.
This is the PHP port of shiny_json_logic, the most compliant Ruby implementation of JSON Logic.
This library was built as a modern, fully spec-compliant alternative to
jwadhams/json-logic-php, which at the
time of writing passes ~69% of the official test suite, has known vulnerabilities in its
dependency tree, and has not seen active maintenance since mid-2024.
shiny/json-logic-php is designed as a drop-in replacement.
- ✅ 100% spec-compliant — the only PHP library that passes all 601 official JSON Logic tests (stdclass mode).
- 🧩 Zero runtime dependencies — stdlib only. Just plug & play.
- 🕰️ PHP 8.1+ compatible.
- 🔧 Actively maintained and aligned with the evolving JSON Logic specification.
- 🔁 Drop-in aliases:
JsonLogicandJSONLogicavailable out of the box.
composer require shiny/json-logic-phpuse ShinyJsonLogic\ShinyJsonLogic;
// Basic evaluation
ShinyJsonLogic::apply(['==' => [1, 1]]);
// → true
// With data
ShinyJsonLogic::apply(['var' => 'name'], ['name' => 'Luis']);
// → "Luis"
// Feature flag example
$rule = ['==' => [['var' => 'plan'], 'premium']];
$data = ['plan' => 'premium'];
ShinyJsonLogic::apply($rule, $data);
// → true
// Nested access
ShinyJsonLogic::apply(['var' => 'user.age'], ['user' => ['age' => 30]]);
// → 30Rules can be nested arbitrarily:
$rule = [
'if' => [
['var' => 'financing'],
['missing' => ['apr']],
[]
]
];
ShinyJsonLogic::apply($rule, ['financing' => true]);
// → ["apr"]JsonLogic and JSONLogic are available as aliases:
JsonLogic::apply(['>' => [['var' => 'score'], 90]], ['score' => 95]);
// → trueIn PHP, json_decode parses a JSON string into either stdclass objects or associative arrays:
json_decode('{"var": "name"}'); // → stdClass { $var: "name" }
json_decode('{"var": "name"}', true); // → ["var" => "name"]Both modes work with this library:
// stdclass mode (recommended — full 601/601 compliance)
$rule = json_decode('{"var": "name"}');
$data = json_decode('{"name": "Luis"}');
ShinyJsonLogic::apply($rule, $data);
// → "Luis"
// arrays mode also works (600/601 — see Compatibility)
$rule = json_decode('{"var": "name"}', true);
$data = json_decode('{"name": "Luis"}', true);
ShinyJsonLogic::apply($rule, $data);
// → "Luis"| Category | Operators |
|---|---|
| Data access | var, missing, missing_some, exists, val ✨ |
| Logic | if, ?:, and, or, !, !! |
| Comparison | ==, ===, !=, !==, >, >=, <, <= |
| Arithmetic | +, -, *, /, %, max, min |
| String | cat, substr |
| Array | map, filter, reduce, all, none, some, merge, in |
| Coalesce | ?? ✨ |
| Error handling | throw, try ✨ |
| Utility | coalesce, preserve ✨, log |
✨ = community-extended operators beyond the core spec.
shiny/json-logic-php uses native PHP exceptions:
// Unknown operators throw an exception
ShinyJsonLogic::apply(['unknown_op' => [1, 2]], []);
// → throws ShinyJsonLogic\Errors\UnknownOperator
// You can use try/throw for controlled error handling within rules
$rule = [
'try' => [
['throw' => 'Something went wrong'],
['cat' => ['Error: ', ['var' => 'type']]]
]
];
ShinyJsonLogic::apply($rule, []);
// → "Error: Something went wrong"Exception classes:
ShinyJsonLogic\Errors\UnknownOperator— unknown operator in ruleShinyJsonLogic\Errors\InvalidArguments— invalid arguments to operatorShinyJsonLogic\Errors\NotANumber— NaN result in numeric operation
Or catch ShinyJsonLogic\Errors\Base to handle all library errors in one sweep.
Tested against the official JSON Logic test suite (601 tests).
| Mode | Passed | Notes |
|---|---|---|
stdclass (json_decode without true) |
601 / 601 | Full compliance |
arrays (json_decode with true) |
600 / 601 | One PHP-language limitation (see below) |
In PHP, json_decode('{}', true) returns [] — an empty array, indistinguishable from json_decode('[]', true). This means that in arrays mode, the engine cannot tell an empty object from an empty array.
The one failing case is the + operator with an empty object passed directly as the operand list:
// stdclass mode — throws NotANumber ✅
ShinyJsonLogic::apply(json_decode('{"+" : {}}'));
// arrays mode — returns 0 instead of NaN ❌
ShinyJsonLogic::apply(json_decode('{"+" : {}}', true));In arrays mode, {"+" : {}} is decoded as ["+" => []] — zero operands — so + returns 0 instead of NaN. In stdclass mode, {} is preserved as an EmptyObject sentinel, and the operator correctly produces NaN.
This is a PHP language limitation, not a bug in this library. The issue has been reported to the json-logic org.
For this reason, if you need full spec compliance or interoperability with other JSON Logic implementations, we strongly recommend using stdclass mode (json_decode without true).
All other 600 tests pass in both modes.
composer install
./vendor/bin/phpunitTo run the official test suite against live test data:
./run-official-tests.shRequires Docker and curl. Fetches the official tests at runtime from github.com/json-logic/.github.
Contributions are welcome — especially:
- spec alignment improvements
- missing operators
- edge-case tests
Please include tests with any change.
Repository: https://github.com/luismoyano/shiny-json-logic-php
- shiny_json_logic (Ruby) — 601/601 official tests, the most compliant Ruby implementation
- jsonlogicruby.com — JSON Logic playground, docs, and specification reference
MIT License.
Use it. Fork it. Ship it. (:
Shine bright like a 🐘