shiny/json-logic-php

A modern, complete PHP implementation of JsonLogic. 601/601 official tests. Zero dependencies. PHP 8.1+.

Maintainers

Package info

github.com/luismoyano/shiny-json-logic-php

pkg:composer/shiny/json-logic-php

Statistics

Installs: 71

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v0.1.1 2026-03-16 18:17 UTC

README

Packagist PHP License: MIT

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.

Why shiny/json-logic-php?

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: JsonLogic and JSONLogic available out of the box.

Installation

composer require shiny/json-logic-php

Usage

use 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]]);
// → 30

Nested logic

Rules can be nested arbitrarily:

$rule = [
    'if' => [
        ['var' => 'financing'],
        ['missing' => ['apr']],
        []
    ]
];

ShinyJsonLogic::apply($rule, ['financing' => true]);
// → ["apr"]

Drop-in aliases

JsonLogic and JSONLogic are available as aliases:

JsonLogic::apply(['>' => [['var' => 'score'], 90]], ['score' => 95]);
// → true

Working with json_decode

In 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"

Supported operators

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.

Error handling

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 rule
  • ShinyJsonLogic\Errors\InvalidArguments — invalid arguments to operator
  • ShinyJsonLogic\Errors\NotANumber — NaN result in numeric operation

Or catch ShinyJsonLogic\Errors\Base to handle all library errors in one sweep.

Compatibility

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)

The arrays mode edge case

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.

Development

composer install
./vendor/bin/phpunit

To run the official test suite against live test data:

./run-official-tests.sh

Requires Docker and curl. Fetches the official tests at runtime from github.com/json-logic/.github.

Contributing

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

Related projects

License

MIT License.

Use it. Fork it. Ship it. (:

Shine bright like a 🐘