ProperNullCoalescingOperatorUsage
info on by default quick-fix PHP ≥ 7.0Group: Code style · PhpStorm name: ProperNullCoalescingOperatorUsageInspection
Two misuses of ??: (a) call() ?? null — a call result never triggers an undefined-index/variable notice, so ?? null does nothing; (b) a fallback whose type has nothing in common with the left operand's type, which usually signals a bug or a confusing API.
Example
With ALLOW_OVERLAPPING_TYPES = false:
php
<?php
interface Shape {}
class Square implements Shape {}
class Disc implements Shape {}
class Engine {}
class Turbo extends Engine {}
class Garage {
/** @var Engine|null */
private $engine;
public function lookup(): ?Engine { return null; }
public function demo(Engine $e, Turbo $t, Square $s, Disc $d, ?int $n = null, string $label = null) {
return [
$this->lookup() ?? null,
strrev($label) ?? NULL,
$this->engine ?? 'none',
$n ?? 'n/a', // scalar placeholder (D5a)
$this->engine ?? null,
$label ?? null,
$t ?? $e,
$e ?? $t,
$s ?? $d, // related through Shape
$n ?? 42,
(int) ($label ?? $e),
];
}
}php
<?php
interface Shape {}
class Square implements Shape {}
class Disc implements Shape {}
class Engine {}
class Turbo extends Engine {}
class Garage {
/** @var Engine|null */
private $engine;
public function lookup(): ?Engine { return null; }
public function demo(Engine $e, Turbo $t, Square $s, Disc $d, ?int $n = null, string $label = null) {
return [
$this->lookup(),
strrev($label),
$this->engine ?? 'none',
$n ?? 'n/a', // scalar placeholder (D5a)
$this->engine ?? null,
$label ?? null,
$t ?? $e,
$e ?? $t,
$s ?? $d, // related through Shape
$n ?? 42,
(int) ($label ?? $e),
];
}
}Reported:
- line 16: '$this->lookup()' alone is equivalent; drop the '?? null' fallback.
- line 17: 'strrev($label)' alone is equivalent; drop the '?? null' fallback.
- line 18: Operand types of '??' do not match ([\Engine] vs [string]).
Options
| Option | Type | Default | Effect |
|---|---|---|---|
| ANALYZE_TYPES | bool | true | Enables Case B (type complementarity). |
| ALLOW_OVERLAPPING_TYPES | bool | true | When true, any shared type makes operands complementary; when false, the right operand's types must cover all of the left operand's types. |
Upstream fixtures run with ANALYZE_TYPES = true and ALLOW_OVERLAPPING_TYPES = false.
Configure
In custos.json:
json
{
"rules": {
"ProperNullCoalescingOperatorUsage": {
"enabled": false,
"options": {
"ANALYZE_TYPES": true,
"ALLOW_OVERLAPPING_TYPES": true
}
}
}
}Suppress
Before the statement or declaration (or the first statement of the file), either of:
php
// @custos-ignore ProperNullCoalescingOperatorUsage
/**
* @noinspection ProperNullCoalescingOperatorUsageInspection
*/