SuspiciousBinaryOperation
error on by default quick-fixGroup: Probable bugs · PhpStorm name: SuspiciousBinaryOperationInspection
Flags binary operations that are almost certainly not what the author meant: instanceof against a trait, identical operands, == used as a statement, >= typed instead of => in an array, a comparison placed inside a call's parentheses, negated comparisons on nullable values, ?? after a cast or !, concatenation with an array literal, hard-coded booleans in &&/||, and mixed &&/||/assignment precedence.
Example
php
<?php
trait Loggable {}
interface Shape {}
function checks($obj, $p, $q, array $tags, ?int $limit) {
$t1 = $obj instanceof Loggable;
$t2 = $obj instanceof Shape;
$s1 = $p->id === ($p->id);
$s2 = count($tags) > count($tags);
$p == $q;
$map = ['enabled' >= true, $p >= 'x'];
$out = [
(bool)$p ?? 0,
(!$q) ?? 1,
$p ?? $q,
];
$msg = 'tags: ' . ['a'];
$ok = [
$p and FALSE,
$p || true,
$p && \true,
$p or null,
];
if (!($limit < 10)) {}
}
class Quota {
public function fits(string $who): bool {
if (strlen($who >= 3)) {}
if ($this->allow($who === 'root')) {}
return true;
}
private function allow(bool $flag) { return $flag; }
}
if ($found = $left != $right) {}
if ($x || $y && $z) {}
if ($row = fetch() || $fallback) {}
if (! $x >= $limit) {}
if (($x && $y) || $z) {}
$both = $x && $y;
if ((!$x) < $y) {}php
<?php
trait Loggable {}
interface Shape {}
function checks($obj, $p, $q, array $tags, ?int $limit) {
$t1 = $obj instanceof Loggable;
$t2 = $obj instanceof Shape;
$s1 = $p->id === ($p->id);
$s2 = count($tags) > count($tags);
$p == $q;
$map = ['enabled' >= true, $p >= 'x'];
$out = [
(bool)$p ?? 0,
(!$q) ?? 1,
$p ?? $q,
];
$msg = 'tags: ' . ['a'];
$ok = [
$p and FALSE,
$p || true,
$p && \true,
$p or null,
];
if ($limit >= 10) {}
}
class Quota {
public function fits(string $who): bool {
if (strlen($who) >= 3) {}
if ($this->allow($who === 'root')) {}
return true;
}
private function allow(bool $flag) { return $flag; }
}
if ($found = ($left != $right)) {}
if ($x || ($y && $z)) {}
if ($row = (fetch() || $fallback)) {}
if ((!$x) >= $limit) {}
if (($x && $y) || $z) {}
$both = $x && $y;
if ((!$x) < $y) {}Reported:
- line 6: A trait is never an instanceof target; this is always false.
- line 8: Both operands are the same.
- line 9: Both operands are the same.
- line 10: Comparison result is discarded; did you mean '='?
- line 11: Did you mean '=>' for an array key?
- line 13: '(bool)$p' is never null, so '??' is useless; add parentheses.
- line 14: '!$q' is never null, so '??' is useless; add parentheses.
- line 17: Concatenating an array literal makes no sense.
- line 19: This constant decides the whole condition.
- line 20: This constant decides the whole condition.
- line 21: This constant has no effect in the condition.
- line 22: This constant has no effect in the condition.
- line 24: Null or false operands make this negated comparison misleading; use '$limit >= 10'.
- line 29: This comparison probably belongs outside the call parentheses.
- line 36: Operator precedence is unclear here; add parentheses.
- line 37: Operator precedence is unclear here; add parentheses.
- line 38: Operator precedence is unclear here; add parentheses.
- line 39: Operator precedence is unclear here; add parentheses.
Options
| Option | Type | Default | Effect |
|---|---|---|---|
VERIFY_CONSTANTS_IN_CONDITIONS | bool | true | Enables D9. |
VERIFY_UNCLEAR_OPERATIONS_PRIORITIES | bool | true | Enables D10. |
Configure
In custos.json:
json
{
"rules": {
"SuspiciousBinaryOperation": {
"enabled": false,
"options": {
"VERIFY_CONSTANTS_IN_CONDITIONS": true,
"VERIFY_UNCLEAR_OPERATIONS_PRIORITIES": true
}
}
}
}Suppress
Before the statement or declaration (or the first statement of the file), either of:
php
// @custos-ignore SuspiciousBinaryOperation
/**
* @noinspection SuspiciousBinaryOperationInspection
*/