Skip to content

Fix == / != to match JavaScript abstract equality for null#23

Open
erikgaal wants to merge 1 commit into
jwadhams:masterfrom
erikgaal:fix/js-null-loose-equality
Open

Fix == / != to match JavaScript abstract equality for null#23
erikgaal wants to merge 1 commit into
jwadhams:masterfrom
erikgaal:fix/js-null-loose-equality

Conversation

@erikgaal

@erikgaal erikgaal commented Jun 25, 2026

Copy link
Copy Markdown

Problem

JsonLogic's value proposition is that a rule evaluates identically on the front end (json-logic-js) and the back end (this library). For null, they diverge:

// json-logic-js
jsonLogic.apply({"==": [null, 0]})  // => false
// json-logic-php
JWadhams\JsonLogic::apply(['==' => [null, 0]]);  // => true  (wrong)

In JavaScript, null is loosely-equal only to null/undefined, never to 0, false, or "". PHP's native == coerces null to those, so == / != return the opposite of the reference implementation whenever an operand is null. This bites real rules: a missing or unanswered field compared with {"==": [{"var": "x"}, 0]} is false in the browser but true here, so client-side visibility and server-side validation disagree.

Fix

Guard the null case in == and != so null is loosely-equal only to null, matching json-logic-js. Non-null comparisons are untouched (PHP 8 already matches JS for those).

'==' => function ($a, $b) {
    if ($a === null || $b === null) {
        return $a === null && $b === null;
    }
    return $a == $b;
},

Tests

The shared jsonlogic.com tests.json parity suite still passes (it has no null-equality cases, which is how this gap went unnoticed). Added tests/NullLooseEqualityTest.php covering null against null, 0, false, "", "0", [] for both == and !=, plus non-null sanity cases.

Scope is intentionally limited to the null divergence; broader JS-coercion edge cases are left as-is.

The JsonLogic format is designed so a rule evaluates identically in
json-logic-js (front end) and this library (back end). For null, the two
diverged:

  {"==": [null, 0]}  =>  json-logic-js: false   json-logic-php: true

In JavaScript, null is loosely-equal only to null/undefined, never to 0,
false or "". PHP's native == coerces null to those, so ==/!= returned the
opposite of the reference implementation whenever an operand was null (for
example a missing or unanswered field compared with "== 0").

Guard the null case in == and != so null is loosely-equal only to null,
matching json-logic-js. Non-null comparisons are unchanged. The shared
jsonlogic.com test suite still passes; added focused coverage for the null
cases.
@erikgaal erikgaal force-pushed the fix/js-null-loose-equality branch from 6a76a66 to bb24f45 Compare June 25, 2026 13:49
@erikgaal erikgaal marked this pull request as ready for review June 25, 2026 15:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant