Who is Elvis and what does he have to do with PHP?
\n\nIf you've ever written in PHP, you've probably seen strange constructs in someone else's code: $name ?: 'Guest' or $name ?? 'Guest'. At first glance, they look the same. But in reality, these two operators hide completely different mechanics that can either save your code or cause trouble.
On Stack Overflow, the question "PHP short-ternary ("Elvis") operator vs null coalescing operator" has gathered tens of thousands of views. And this is no coincidence. Developers get confused, make mistakes, and then spend a long time hunting for bugs. Let's finally figure out who is who, and stop guessing.
\n\nIn this article, we won't just list the differences. We'll look under the hood of PHP, examine real production cases, and understand when to use which operator. Let's go!
\n\nQuick primer: what are these anyway?
\n\nTernary operator (classic)
\nFirst, let's recall the basics. The ternary operator is a shortened form of if-else:
\n\n$age = 20;\n$status = ($age >= 18) ? 'Adult' : 'Child';\n// $status = 'Adult'\n\nSimple: if the condition is true, take the first value; otherwise, take the second.
\n\nShort-ternary (aka Elvis operator) — ?:
\nThis is a shortcut for when you are checking a variable for "truthiness" and want to use its value:
\n\n$name = 'Alexey';\n$greeting = $name ?: 'Guest';\n// $greeting = 'Alexey'\n\n$name = '';\n$greeting = $name ?: 'Guest';\n// $greeting = 'Guest'\n\nIt works like this: if $name evaluates to true, take $name. Otherwise, take "Guest".
Null coalescing operator — ??
\nIt appeared in PHP 7.0 and immediately became a developer favorite:
\n\n$name = 'Alexey';\n$greeting = $name ?? 'Guest';\n// $greeting = 'Alexey'\n\n$name = null;\n$greeting = $name ?? 'Guest';\n// $greeting = 'Guest'\n\nThe difference from Elvis: the check is only for null, not for "falsiness" in general.
\n\nMain difference: what is considered "empty"?
\n\nThis is where it gets interesting. Let's look at a comparison table for different $value values:
$value = false;\necho $value ?: 'default'; // 'default' (false is "falsy")\necho $value ?? 'default'; // false (false is NOT null)\n\n$value = 0;\necho $value ?: 'default'; // 'default' (0 is "falsy")\necho $value ?? 'default'; // 0 (0 is NOT null)\n\n$value = '';\necho $value ?: 'default'; // 'default' (empty string is "falsy")\necho $value ?? 'default'; // '' (empty string is NOT null)\n\n$value = [];\necho $value ?: 'default'; // 'default' (empty array is "falsy")\necho $value ?? 'default'; // [] (empty array is NOT null)\n\n$value = '0';\necho $value ?: 'default'; // 'default' (string "0" is "falsy"!)\necho $value ?? 'default'; // '0' (string "0" is NOT null)\n\nSee the difference? Elvis works as a truthy/falsy check, while null coalescing is a strict check for existence and difference from null.
\n\nUnder the hood: how it works at the engine level
\n\nLet's look into the PHP source code (well, almost). If you've ever compiled PHP from source, you know that both operators are processed at the parsing stage.
\n\nShort-ternary (?):
\nIn fact, it's syntactic sugar. $a ?: $b becomes $a ? $a : $b. But there's a nuance: PHP does not evaluate $a twice. It saves the result in a temporary variable. This is important for functions with side effects:
function getData() {\n echo "Function called!\\n";\n return rand(0, 1) ? 'data' : '';\n}\n\n// Elvis calls the function ONCE\n$result = getData() ?: 'default';\n// "Function called!" — once\n\nIf PHP evaluated $a twice,