Bad Null Guard
ID |
php.bad_null_guard |
Severity |
high |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Reliability |
Language |
Php |
Tags |
null-safety, reliability |
Description
Reports an inverted null guard: a condition whose left operand tests a variable for null and
whose right operand dereferences that same variable in the branch where it is known to be
null. The dereference is reached precisely when the variable holds null, so the call fails at
runtime.
Rationale
A correct guard short-circuits the dereference away from the null case: $x !== null && $x→m()
calls the method only when $x is non-null. Flipping the test — $x == null && $x→m() — keeps
the same code shape but inverts the meaning: the && reaches $x→m() only when $x == null is
true, i.e. exactly when $x is null. The same trap appears as is_null($x) && $x→m(),
!isset($x) && $x→m(), and the OR dual $x !== null || $x→m() (the || falls through to the
dereference only when $x is null). All four dereference null whenever the branch runs.
<?php
function process($user)
{
if ($user == null && $user->save()) { // FLAW — $user->save() runs only when $user is null
return;
}
if ($user !== null && $user->save()) { // OK — dereference reached only when non-null
return;
}
}
Remediation
Invert the null test so the dereference is reached only when the variable is non-null: replace
==/=== with !== (and || with &&), or is_null($x) / !isset($x) with isset($x).
If the test direction is correct, the dereference belongs in the other branch.