Question
PHP Elvis Operator (?:) vs Null Coalescing Operator (??)
Question
In PHP, what is the difference between the short ternary operator (?:) and the null coalescing operator (??)?
When do these two expressions behave differently, and when do they produce the same result?
$a ?: $b
$a ?? $b
Short Answer
By the end of this page, you will understand how PHP's short ternary operator ?: and null coalescing operator ?? decide whether to return the left or right value. You will learn the key difference between falsy checks and null-or-undefined checks, see where they behave the same, and know which one to choose in real PHP code.
Concept
The two operators look similar, but they solve different problems.
?:is the short ternary operator, often called the Elvis operator.??is the null coalescing operator.
Their difference comes from what they test.
?: checks for truthiness
$result = $a ?: $b;
This means:
$result = $a ? $a : $b;
So PHP evaluates $a as a boolean.
If $a is truthy, the result is $a.
If $a is falsy, the result is $b.
In PHP, common falsy values include:
false00.0"""0"[]null
?? checks for null or missing values
$result = $a ?? $b;
This means roughly:
$result = isset($a) ? $a : $b;
So ?? does not care whether $a is truthy or falsy. It only cares whether $a:
- exists, and
- is not
null
If $a is set and not null, PHP returns $a.
If $a is undefined or null, PHP returns $b.
Why this matters
In real programs, values like 0, "", or false are often valid data.
For example:
- a quantity of
0 - an empty search string
"" - a boolean setting
false
If you use ?:, those values are treated as "use the fallback".
If you use ??, those values are preserved.
That makes ?? especially useful for:
- request input
- configuration values
- optional array keys
- default values for variables that may be missing
Use ?: when you want a fallback for any falsy value.
Use ?? when you want a fallback only for null or undefined values.
Mental Model
Think of the two operators as two different gatekeepers.
?: is a strict "does this look usable?" gatekeeper
It looks at the value and says:
- "If this is truthy, keep it."
- "If this is falsy, replace it."
So values like 0 or "" get rejected, even if they are meaningful.
?? is a "is anything actually missing?" gatekeeper
It asks:
- "Is there a value here?"
- "Is it not null?"
If the answer is yes, it keeps the value, even if that value is 0, false, or "".
Simple analogy
Imagine filling out a form:
?:says: "This field looks empty or weak, so I will use the backup."??says: "I only use the backup if the field was not filled in at all, or was explicitly null."
That is the core difference: falsy vs missing/null.
Syntax and Examples
Core syntax
$a ?: $b
$a ?? $b
Expanded forms
$a ?: $b // same as: $a ? $a : $b
$a ?? $b // similar to: isset($a) ? $a : $b
Example 1: value is 0
$a = 0;
$b = 100;
echo $a ?: $b; // 100
echo "\n";
echo $a ?? $b; // 0
Why?
0is falsy, so?:returns$b0is not null, so??returns$a
Example 2: value is null
$a = null;
$b = 'fallback';
echo $a ?: $b; // fallback
echo "\n";
echo $a ?? $b; // fallback
Here they behave the same because null is both:
- falsy
- considered missing by
??
Example 3: value is an empty string
$a = "";
$b = "default";
echo $a ?: $b; // default
echo "\n";
echo $a ?? $b; // ""
Why?
""is falsy, so?:uses the fallback""is set and not null, so??keeps it
Example 4: undefined variable
// $a is not defined
$b = 'fallback';
$result1 = $a ?? $b; // fallback
This is a common use case for ??.
With ?:, using an undefined variable is problematic because PHP must evaluate $a directly.
// $a is not defined
$result2 = $a ?: $b; // may raise a notice/warning depending on PHP version/settings
Example 5: boolean false
$a = false;
$b = true;
var_dump($a ?: $b); // bool(true)
var_dump($a ?? $b); // bool(false)
This is one of the most important practical differences.
Step by Step Execution
Consider this code:
$a = 0;
$b = 5;
$x = $a ?: $b;
$y = $a ?? $b;
Step-by-step for $x = $a ?: $b;
- PHP reads
$a. - PHP converts
$ato a boolean for the condition. $ais0, which is falsy.- Because the condition is false, PHP returns
$b. $xbecomes5.
Step-by-step for $y = $a ?? $b;
- PHP checks whether
$ais set and notnull. $aexists.$ais0, notnull.- PHP keeps
$a. $ybecomes0.
Final values
var_dump($x); // int(5)
var_dump($y); // int(0)
Another trace with null
$a = null;
$b = 5;
$x = $a ?: $b;
$y = $a ?? $b;
?:seesnullas falsy, so$xbecomes5??seesnullas missing, so$ybecomes5
In this case, both produce the same result.
Real World Use Cases
Use ?? for optional input and defaults
Request parameters
$page = $_GET['page'] ?? 1;
$search = $_GET['search'] ?? '';
This is useful because the key may not exist at all.
Configuration values
$host = $config['host'] ?? 'localhost';
$port = $config['port'] ?? 3306;
If the config key is missing or null, a default is used.
Nested data access
$username = $user['profile']['username'] ?? 'guest';
Use ?: when any falsy value should trigger a fallback
Display label fallback
$label = trim($input) ?: 'Untitled';
If the trimmed input becomes an empty string, use 'Untitled'.
Optional computed result
$slug = generateSlug($title) ?: 'default-slug';
If slug generation returns an empty string, use a fallback.
Post-validation cleanup
$name = $name ?: 'Anonymous';
This only makes sense if values like "", false, or 0 should all be treated as unusable.
A practical rule
- Use
??for missing data - Use
?:for empty/falsy data
Real Codebase Usage
In real PHP projects, developers often use these operators in predictable patterns.
Pattern: safe defaults from arrays and request data
$sort = $_GET['sort'] ?? 'created_at';
$limit = $_GET['limit'] ?? 20;
This avoids notices for missing keys and keeps valid falsy values if they exist.
Pattern: environment and configuration fallback
$env = $_ENV['APP_ENV'] ?? 'production';
$debug = $config['debug'] ?? false;
This is common in framework bootstrapping and config loading.
Pattern: normalize output after processing
$title = trim($title) ?: 'Untitled';
After transforming data, ?: is useful when an empty result should be replaced.
Pattern: guard clause with defaults
function renderTitle(?string $title): string {
return $title ?? 'Default Title';
}
If null means "no value provided," ?? is the right choice.
Pattern: preserving meaningful false and 0
$isEnabled = $settings['enabled'] ?? true;
$retryCount = $options['retries'] ?? 3;
If the actual stored value is false or 0, ?? keeps it. That is usually what you want in configuration code.
Pattern: fallback after validation
$nickname = trim($nickname);
$nickname = $nickname ?: 'guest';
Here an empty string after trimming should be replaced, so ?: fits.
Good team habit
A lot of bugs come from choosing ?: when 0, false, or "" are valid values. In production code, ?? is often safer for defaults.
Common Mistakes
Mistake 1: using ?: when 0 is a valid value
$quantity = 0;
echo $quantity ?: 10; // 10
If 0 is a meaningful value, this is wrong.
Better
echo $quantity ?? 10; // 0
Mistake 2: using ?: with false when false is a real setting
$enabled = false;
$result = $enabled ?: true; // true
This overwrites a valid false value.
Better
$result = $enabled ?? true; // false
Mistake 3: expecting ?? to treat empty strings as missing
$name = "";
echo $name ?? 'Anonymous'; // ""
If you want empty strings to fall back too, ?? is not enough.
Better
echo $name ?: 'Anonymous'; // Anonymous
Or make the rule explicit:
echo trim($name) === '' ? 'Anonymous' : $name;
Mistake 4: forgetting that undefined variables behave differently
// $value not defined
$result = $value ?: 'fallback';
This can raise notices or warnings because $value must be evaluated.
Better
$result = $value ?? 'fallback';
Mistake 5: assuming ?: and ?? are interchangeable
They are only the same when the left side is both:
- falsy, and
null
For example:
$a = null;
var_dump($a ?: 'x'); // x
var_dump($a ?? 'x'); // x
But they differ for many other values:
$a = 0;
var_dump($a ?: 'x'); // x
var_dump($a ?? 'x'); // 0
Comparisons
| Operator | What it checks | Returns right side when left side is... | Preserves 0 | Preserves false | Preserves "" | Safe for undefined variable |
|---|---|---|---|---|---|---|
?: | Truthiness | falsy | No | No | No | No |
?? | isset()-style null check | undefined or null | Yes | Yes | Yes | Yes |
Same result cases
They produce the same result when the left side is:
null
Example:
$a = null;
$b = 'fallback';
var_dump($a ?: $b); // fallback
var_dump($a ?? $b); // fallback
Different result cases
They behave differently when the left side is a falsy value that is not null.
| Left value | $a ?: $b | $a ?? $b |
|---|---|---|
0 | $b | 0 |
false | $b | false |
"" | $b | "" |
"0" | $b | "0" |
[] | $b | [] |
Compared with full ternary
| Expression | Meaning |
|---|---|
$a ? $x : $y | If $a is truthy, return $x, else $y |
$a ?: $b | If $a is truthy, return $a, else $b |
$a ?? $b | If $a exists and is not null, return $a, else $b |
Cheat Sheet
$a ?: $b // uses $b if $a is falsy
$a ?? $b // uses $b if $a is undefined or null
Use ?: when
- you want to reject all falsy values
- empty strings should fall back
0andfalseshould also fall back
Use ?? when
- a variable or array key may be missing
nullshould trigger the default0,false, and""are valid values
Falsy values in PHP
These make ?: choose the right side:
false00.0"""0"[]null
Quick examples
0 ?: 5 // 5
0 ?? 5 // 0
false ?: true // true
false ?? true // false
'' ?: 'x' // 'x'
'' ?? 'x' // ''
null ?: 'x' // 'x'
null ?? 'x' // 'x'
Rule of thumb
?:= fallback for falsy??= fallback for null or missing
FAQ
What is the difference between ?: and ?? in PHP?
?: checks whether the left value is truthy. ?? checks whether the left value exists and is not null.
Does ?? behave like isset()?
Yes. a ?? b is roughly equivalent to isset($a) ? $a : $b.
Does ?: treat 0 as empty?
Yes. Since 0 is falsy in PHP, ?: will use the fallback value.
When do ?: and ?? return the same result?
They return the same result when the left side is null.
Which operator should I use for $_GET or $_POST values?
Usually ??, because request keys may be missing and values like 0 or "" may still be valid.
Why does ?: fail with undefined variables?
Because PHP must evaluate the left side directly. ?? is designed to handle undefined variables or missing array keys safely.
Is ?? better than ?:?
Not always. ?? is better for missing or null values. ?: is better when any falsy value should trigger a fallback.
Mini Project
Description
Build a small PHP script that reads optional user settings and displays final values with sensible defaults. This project demonstrates the practical difference between ?: and ?? when handling missing data, empty strings, zero values, and boolean flags.
Goal
Create a script that shows when to preserve valid falsy values with ?? and when to replace empty-style values with ?:.
Requirements
- Create variables representing optional settings such as username, page number, and dark mode.
- Use
??for values that may be missing or null. - Use
?:for a display value where an empty string should fall back. - Print the final resolved values so the difference is visible.
Keep learning
Related questions
Are PDO Prepared Statements Enough to Prevent SQL Injection in PHP?
Learn how PDO prepared statements prevent SQL injection in PHP, what they protect, and the mistakes that still leave MySQL apps vulnerable.
Can You Bind an Array to an IN Clause in PHP PDO?
Learn how PDO handles placeholders in IN() clauses, why arrays cannot be bound directly, and the safe PHP pattern to build dynamic queries.
Choosing the Right MySQL Collation for PHP and UTF-8
Learn how MySQL character sets and collations work with PHP, and how to choose a practical UTF-8 setup for web applications.