01 · THE IDEAREAD → TRY → LEARN
What null means
In PHP, null is a type with exactly one value, and it means "no value here". It is not the same as an empty string, the number zero, the string "0", false or an empty array. Those are all real values. A user who typed nothing into a form gave you ""; a user who chose a volume of zero gave you 0; a key that was never provided gives you nothing at all. Treating these cases the same is one of the most common sources of quiet bugs.
The strict comparison === null is the dependable way to ask "is this missing?". Loose comparison with == applies type juggling. The comparison table in the manual says that when either side is null or a bool, both sides are converted to booleans, so null == false and null == 0 are both true. That is rarely what you want when you are looking for absence.
Seeing the differences
The first example runs several "empty-looking" values through a strict null check.
$values = [null, '', 0, '0', false, []];
foreach ($values as $value) {
echo json_encode($value), ' ', var_export($value === null, true), "\n";
}null true "" false 0 false "0" false false false [] false
Only the first value is identical to null. Everything else is a legitimate value that happens to be falsy.
The null-coalescing operator
The expression $a ?? $b evaluates to $a when $a exists and is not null, and to $b otherwise. It also stays silent when the left side is an undefined variable or a missing array key, much like isset(). That makes it ideal for reading optional input.
$settings = ['theme' => null, 'volume' => 0, 'title' => ''];
echo json_encode([
$settings['theme'] ?? 'light',
$settings['volume'] ?? 5,
$settings['title'] ?? 'Untitled',
$settings['language'] ?? 'en',
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";["light",0,"","en"]
The null theme and the missing language both fall back to defaults. The volume of 0 and the empty title are kept, because neither is null. That is the whole point: ?? replaces only absence.
?? versus ?:
The short ternary $a ?: $b is different. It picks $b whenever $a is falsy, which includes 0, "", "0", false and []. Use it only when every falsy value really should be replaced. A retry count of 0 is a deliberate choice, so replacing it with a default would change the meaning of the configuration. Also, ?: does not suppress the warning for an undefined array key, while ?? does.
There is also the assignment form ??=, which assigns the right side only when the left side is missing or null. It is handy for filling in defaults in an array.
$config = ['retries' => 0, 'name' => null];
$a = $config['retries'] ?? 3;
$b = $config['retries'] ?: 3;
$config['name'] ??= 'anonymous';
$config['mode'] ??= 'safe';
echo json_encode(['coalesce' => $a, 'elvis' => $b, 'config' => $config], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";{"coalesce":0,"elvis":3,"config":{"retries":0,"name":"anonymous","mode":"safe"}}
Notice that retries stays 0 after ??= is applied to other keys, and the ?? result is 0, while ?: produced 3.
Precedence and chaining
The ?? operator has low precedence. Mixing it with concatenation or arithmetic usually needs parentheses: write 'Mr. ' . ($name ?? 'Anonymous'), not 'Mr. ' . $name ?? 'Anonymous', because in the second form the concatenation happens first and the undefined variable is read before the default can help. You can chain it as well: $a ?? $b ?? $c returns the first operand that exists and is not null.
Common mistakes
- Using
empty()or?:to detect a missing value, which also discards0and"0". - Comparing with
==and getting a surprise becausenull == false. - Forgetting parentheses around a
??expression inside a larger expression. - Using a default for a key that must be present. If missing data is an error, validate and fail loudly instead of hiding it.
Exercise contract
Write a function nicknameOrGuest(array $profile): string. If the profile has a nickname key whose value is not null, return that value unchanged. If the key is missing or its value is null, return "Guest". An empty string nickname and the string "0" are real values and must be returned as they are. The checks compare the returned strings, so do not print anything.
Recap
null means absence, and it is distinct from "", 0, "0", false and []. Test for it with === null. Use ?? to supply a default only for missing or null values, ??= to fill in defaults, and reserve ?: for cases where any falsy value should be replaced.
Associative arrays
- Distinguish null from an empty string or zero
- Choose defaults with the null-coalescing operator