PHPTernary Operator

Ternary Operator

The ternary operator is PHP's compact way of writing a simple if / else as a single expression instead of a multi-line statement. It takes three operands — a condition, a value for when the condition is true, and a value for when it is false — which is why it is called "ternary" (three parts). Once you get comfortable with it, the ternary operator becomes a natural fit for short assignments, default values, and inline decisions inside echo statements or function calls. Used carelessly, though, it can also turn readable code into a puzzle, so this page covers both the syntax and the judgment calls around it.

The basic form

The full syntax is condition ? valueIfTrue : valueIfFalse. PHP evaluates condition, converts it to a boolean if it is not one already, and then evaluates and returns exactly one of the two remaining operands — never both.

A simple ternary assignment

PHP
<?php
$age = 20;

$status = $age >= 18 ? "adult" : "minor";

echo $status;
adult

This is functionally identical to the longer if / else version below — the ternary is just an expression form, so it can appear anywhere a value is expected, including directly inside an echo.

The equivalent if / else

PHP
<?php
$age = 20;

if ($age >= 18) {
    $status = "adult";
} else {
    $status = "minor";
}

echo $status;
Using it inline

Because the ternary operator produces a value rather than a statement, it is often used directly inside string interpolation, function arguments, or echo calls, without needing an intermediate variable.

Inline usage

PHP
<?php
$cartCount = 3;

echo "You have {$cartCount} " . ($cartCount === 1 ? "item" : "items") . " in your cart.";
You have 3 items in your cart.
The shorthand form (the "Elvis operator")

PHP also supports a two-part shorthand: condition ?: valueIfFalse. When the middle operand is left out like this, PHP evaluates condition once, and if it is truthy, returns condition itself rather than re-evaluating it or returning true. If condition is falsy, it returns valueIfFalse. This shape resembles a sideways smiley face, which is why developers nicknamed it the "Elvis operator."

Shorthand ternary in action

PHP
<?php
$nickname = "";
$username = "j_doe";

$displayName = $nickname ?: $username;

echo $displayName;
j_doe

The shorthand form is especially handy for picking the first "truthy" value out of two candidates, such as falling back to a default when a form field was submitted empty. Remember that this checks general truthiness, not just emptiness or nullness — a value of 0, 0.0, "0", false, null, or an empty array or string will all be treated as falsy and trigger the fallback.

Truthiness, not just null, decides the outcome

PHP
<?php
$discount = 0;

$appliedDiscount = $discount ?: 10;

echo $appliedDiscount;
10

Here 0 is a perfectly valid, intentional discount value, but the Elvis operator cannot tell "zero on purpose" apart from "nothing was set," so it silently replaces it with 10. This is one of the most common surprises with the shorthand ternary.

Nested ternaries hurt readability
Avoid stacking ternaries
It is technically legal to nest one ternary inside another to cover more than two outcomes, but the result is notoriously hard to read and easy to misjudge, especially once parentheses are missing or the conditions get longer. PHP itself requires explicit parentheses for nested ternaries precisely because the unparenthesized form was a frequent source of bugs in older code.

Hard to read: nested ternaries

PHP
<?php
$score = 72;

$grade = $score >= 90 ? "A" : ($score >= 75 ? "B" : ($score >= 60 ? "C" : "F"));

echo $grade;
C

The line above works, but a reader has to mentally unwind three levels of parentheses to figure out which branch produced "C". Rewriting the same logic with if / elseif (or, when the branches are simple equality checks, a match expression) reads top to bottom without any nesting to untangle.

Clearer: if / elseif

PHP
<?php
$score = 72;

if ($score >= 90) {
    $grade = "A";
} elseif ($score >= 75) {
    $grade = "B";
} elseif ($score >= 60) {
    $grade = "C";
} else {
    $grade = "F";
}

echo $grade;
C
Ternary vs. the null coalescing operator

PHP 7 introduced ??, the null coalescing operator, specifically to fix the "is this set and not null" pattern that the ternary operator handled clumsily. $value ?? $default checks whether $value is isset() — meaning it exists and is not null — and returns $default only in that case. Unlike the Elvis operator, ?? does not care about general truthiness: 0, false, "", and [] are all left alone because they are set and non-null.

?? only cares about isset / null

PHP
<?php
$discount = 0;
$appliedDiscount = $discount ?? 10;
echo $appliedDiscount;
echo "\n";

$page = $_GET['page'] ?? 1;
echo $page;
0
1

Notice how $discount survives untouched this time, because 0 is set and not null — this is the exact case where the earlier Elvis example gave the wrong answer. ?? also has an added convenience: it will not raise a warning if the left-hand side is an undefined variable or array key, which makes it the standard tool for reading optional array entries like $_GET or $_POST.

  • Use the full ternary (cond ? a : b) when the true and false branches are genuinely different expressions, not just "value or fallback."

  • Use the shorthand Elvis operator (cond ?: b) when you want to keep a value as-is if it is truthy, and any falsy value (including 0 or "") should trigger the fallback.

  • Use the null coalescing operator (cond ?? b) when you specifically want to fall back only on an unset or null value, and treat 0, false, and "" as legitimate data.

  • For three or more branches based on distinct conditions, reach for if / elseif or a match expression instead of nesting ternaries.

Chaining null coalescing

?? can be chained to check several candidates in order, returning the first one that is set and non-null.

Chained null coalescing

PHP
<?php
$config = [];

$timeout = $config['timeout'] ?? $_ENV['APP_TIMEOUT'] ?? 30;

echo $timeout;
30
Tip
When you reach for a ternary purely to supply a default value, pause and ask whether you actually mean "falsy" or "unset/null." If you mean the latter — which is by far the more common intent for things like array keys, query parameters, or optional function arguments — `??` is both shorter and safer than `?:`, since it will not accidentally discard legitimate values like `0` or `""`.