PHP ternary operator vs null coalescing operator
Solution 1
When your first argument is null, they're basically the same except that the null coalescing won't output an E_NOTICE
when you have an undefined variable. The PHP 7.0 migration docs has this to say:
The null coalescing operator (??) has been added as syntactic sugar for the common case of needing to use a ternary in conjunction with isset(). It returns its first operand if it exists and is not NULL; otherwise it returns its second operand.
Here's some example code to demonstrate this:
<?php
$a = null;
print $a ?? 'b'; // b
print "\n";
print $a ?: 'b'; // b
print "\n";
print $c ?? 'a'; // a
print "\n";
print $c ?: 'a'; // Notice: Undefined variable: c in /in/apAIb on line 14
print "\n";
$b = array('a' => null);
print $b['a'] ?? 'd'; // d
print "\n";
print $b['a'] ?: 'd'; // d
print "\n";
print $b['c'] ?? 'e'; // e
print "\n";
print $b['c'] ?: 'e'; // Notice: Undefined index: c in /in/apAIb on line 33
print "\n";
The lines that have the notice are the ones where I'm using the shorthand ternary operator as opposed to the null coalescing operator. However, even with the notice, PHP will give the same response back.
Execute the code: https://3v4l.org/McavC
Of course, this is always assuming the first argument is null
. Once it's no longer null, then you end up with differences in that the ??
operator would always return the first argument while the ?:
shorthand would only if the first argument was truthy, and that relies on how PHP would type-cast things to a boolean.
So:
$a = false ?? 'f'; // false
$b = false ?: 'g'; // 'g'
would then have $a
be equal to false
and $b
equal to 'g'
.
Solution 2
Ran the below on php interactive mode (php -a
on terminal). The comment on each line shows the result.
var_export (false ?? 'value2'); // false
var_export (true ?? 'value2'); // true
var_export (null ?? 'value2'); // value2
var_export ('' ?? 'value2'); // ""
var_export (0 ?? 'value2'); // 0
var_export (false ?: 'value2'); // value2
var_export (true ?: 'value2'); // true
var_export (null ?: 'value2'); // value2
var_export ('' ?: 'value2'); // value2
var_export (0 ?: 'value2'); // value2
The Null Coalescing Operator ??
-
??
is like a "gate" that only lets NULL through. - So, it always returns first parameter, unless first parameter happens to be
NULL
. - This means
??
is same as( !isset() || is_null() )
Use of ??
- shorten
!isset() || is_null()
check - e.g
$object = $object ?? new objClassName();
Stacking Null Coalese Operator
$v = $x ?? $y ?? $z;
// This is a sequence of "SET && NOT NULL"s:
if( $x && !is_null($x) ){
return $x;
} else if( $y && !is_null($y) ){
return $y;
} else {
return $z;
}
The Ternary Operator ?:
?:
is like a gate that letsanything falsy
through - includingNULL
- Anything falsy:
0
,empty string
,NULL
,false
,!isset()
,empty()
- Same like old ternary operator:
X ? Y : Z
- Note:
?:
will throwPHP NOTICE
on undefined (unset
or!isset()
) variables
Use of ?:
- checking
empty()
,!isset()
,is_null()
etc - shorten ternary operation like
!empty($x) ? $x : $y
to$x ?: $y
- shorten
if(!$x) { echo $x; } else { echo $y; }
toecho $x ?: $y
Stacking Ternary Operator
echo 0 ?: 1 ?: 2 ?: 3; //1
echo 1 ?: 0 ?: 3 ?: 2; //1
echo 2 ?: 1 ?: 0 ?: 3; //2
echo 3 ?: 2 ?: 1 ?: 0; //3
echo 0 ?: 1 ?: 2 ?: 3; //1
echo 0 ?: 0 ?: 2 ?: 3; //2
echo 0 ?: 0 ?: 0 ?: 3; //3
// Source & Credit: http://php.net/manual/en/language.operators.comparison.php#95997
// This is basically a sequence of:
if( truthy ) {}
else if(truthy ) {}
else if(truthy ) {}
..
else {}
Stacking both, we can shorten this:
if( isset($_GET['name']) && !is_null($_GET['name'])) {
$name = $_GET['name'];
} else if( !empty($user_name) ) {
$name = $user_name;
} else {
$name = 'anonymous';
}
To this:
$name = $_GET['name'] ?? $user_name ?: 'anonymous';
Cool, right? :-)
Solution 3
If you use the shortcut ternary operator like this, it will cause a notice if $_GET['username']
is not set:
$val = $_GET['username'] ?: 'default';
So instead you have to do something like this:
$val = isset($_GET['username']) ? $_GET['username'] : 'default';
The null coalescing operator is equivalent to the above statement, and will return 'default' if $_GET['username']
is not set or is null
:
$val = $_GET['username'] ?? 'default';
Note that it does not check truthiness. It checks only if it is set and not null.
You can also do this, and the first defined (set and not null
) value will be returned:
$val = $input1 ?? $input2 ?? $input3 ?? 'default';
Now that is a proper coalescing operator.
Solution 4
The major difference is that
Ternary Operator expression
expr1 ?: expr3
returnsexpr1
ifexpr1
evaluates toTRUE
but on the other hand Null Coalescing Operator expression(expr1) ?? (expr2)
evaluates toexpr1
ifexpr1
is notNULL
Ternary Operator
expr1 ?: expr3
emit a notice if the left-hand side value(expr1)
does not exist but on the other hand Null Coalescing Operator(expr1) ?? (expr2)
In particular, does not emit a notice if the left-hand side value(expr1)
does not exist, just likeisset()
.-
TernaryOperator is left associative
((true ? 'true' : false) ? 't' : 'f');
Null Coalescing Operator is right associative
($a ?? ($b ?? $c));
Now lets explain the difference between by example :
Ternary Operator (?:)
$x='';
$value=($x)?:'default';
var_dump($value);
// The above is identical to this if/else statement
if($x){
$value=$x;
}
else{
$value='default';
}
var_dump($value);
Null Coalescing Operator (??)
$value=($x)??'default';
var_dump($value);
// The above is identical to this if/else statement
if(isset($x)){
$value=$x;
}
else{
$value='default';
}
var_dump($value);
Here is the table that explain the difference and similarity between '??'
and ?:
Special Note : null coalescing operator and ternary operator is an expression, and that it doesn't evaluate to a variable, but to the result of an expression. This is important to know if you want to return a variable by reference. The statement return $foo ?? $bar; and return $var == 42 ? $a : $b; in a return-by-reference function will therefore not work and a warning is issued.
Solution 5
Both of them behave differently when it comes to dynamic data handling.
If the variable is empty ( '' ) the null coalescing will treat the variable as true but the shorthand ternary operator won't. And that's something to have in mind.
$a = NULL;
$c = '';
print $a ?? '1b';
print "\n";
print $a ?: '2b';
print "\n";
print $c ?? '1d';
print "\n";
print $c ?: '2d';
print "\n";
print $e ?? '1f';
print "\n";
print $e ?: '2f';
And the output:
1b
2b
2d
1f
Notice: Undefined variable: e in /in/ZBAa1 on line 21
2f
Link: https://3v4l.org/ZBAa1
balping
Updated on December 02, 2021Comments
-
balping over 2 years
Can someone explain the differences between ternary operator shorthand (
?:
) and null coalescing operator (??
) in PHP?When do they behave differently and when in the same way (if that even happens)?
$a ?: $b
VS.
$a ?? $b
-
Mark Baker over 8 yearsPlease don't consider chaining... it's as difficult to read/understand as chained ternaries
-
Script47 over 8 years@MarkBaker this is simply the example from PHP's site. I'll be updating the post to say how it is not advised.
-
NikiC over 8 years@MarkBaker Chained ternaries are hard to understand because PHP has broken ternary associativity. This does not apply to the coalesce operator and imho chained coalesce is perfectly understandable.
-
earl3s almost 8 yearsI disagree. Chaining the null coalesce is a great feature, and it doesn't make it hard to read if you understand the operator. It's commonly used in javascript and once people get comfortable with it in PHP this call to not use chaining should stop. Chaining ternaries is very hard to read, but null coalesce is easy. As you read from left to right it just lists which value should be used next.
-
fregante over 7 yearsThis looks very much like the common
a || b || c
pattern in JS, except PHP's can be used for booleans (false || 2
in JS is 2;false ?? 2
in PHP is false) -
kurdtpage over 7 yearsI disagree with you and others regarding not using chaining. It's like saying dont ever use for loops because might not understand them. Developers/coders are perfectly free to use coding standards and practices that they understand, even if others do not. Personally, I view chained coalescing as very similar to switch statements. It returns the first value that is found (set), and the last value if nothing is found.
-
Damian Green almost 7 yearsTip: if you have been using ?? instead of ?: but then find yourself needing to make your code compatible with PHP versions older than 7(for a plugin for ex), then you may want to swap out the ?? with isset($something) ? $something : $something_else everywhere in your code. You can easily do this with Notepad++ or nedit (and other editors too) using the find/replace tool, selecting the regular expression option and inserting in the find field: "\s*(\S+)\s*\?\?" and in the replace field: " isset($1) ? $1 :" without the quotes (nedit uses \1 instead of $1). Then replace all.
-
mancze almost 7 yearsThis is the right answer however the truthiness check is the major diference and should be more emphasized.
-
RedSparr0w over 6 yearsyou can use $var = $false ?? null ?: "String is empty/false/null/undefined";
-
Dhairya Lakhera over 6 years@MasterOdin Not satisfied with your answer. Both are not same. Have different result.
-
Blaine Lafreniere over 6 yearsWhoa... the
?? null ?:
thing is pretty awesome, thank you mr. clever guy. -
Choxx about 5 yearsGood catch. Also, coalescing-operator will also fail in case of an empty string.
-
Yaron U. almost 5 years
isset($_POST['fullname'])
already checks forNULL
values - so the&& !is_null($_POST['fullname'])
in the first example is redundant anyway -
Simon over 4 yearsThis is clearly counter intuitive for PHP, where an empty string is usually considered false. Yet it is clearly indicated in the docs for ??:
It returns its first operand if it exists and is not NULL; otherwise it returns its second operand
. -
Jack B over 4 yearsIt's worth noting that you can use ?? with chaining. For example:
$b = []; var_dump($b['a']['b']['c'] ?? 'default');
or with objects$b = new Foo; var_dump($b->a()->b()->c() ?? 'default');
-
Doin about 4 yearsThere should be no
$a =
in the above expansion of??
.$a ?? 'fallback'
does not set or change the value of $a. (It merely returns a value). -
Soullivaneuh about 4 yearsPlease be aware that the behavior is also different with
$a = [];
. See: 3v4l.org/iCCa0 -
Soul Reaver over 3 yearsSuperior, except for one mistake: shorten
if(!$x) { echo $x; } else { echo $y; }
toecho $x ?: $y
. One does not equal the other. The condition has to beif($x)
instead, without negation. It still has let me to learn a bit about this operator that was new to me in it's short version, so post received an upvote. -
mickmackusa over 3 yearsIn php, please always use
elseif
as a single word to align with PSR-12 coding standards. I know that you were just making a demonstration, butisset($_GET['name']) && !is_null($_GET['name'])
in the first place is redundant checking. -
Liam about 3 yearsThis is a very good answer to learn how these operators work, but I hope I never have to troubleshoot production code that uses both operators in one statement!
-
St3an almost 3 yearsIn order no to have a notice generated, one should use
$var = empty($other_var) ? 'default_value' : $other_var;
. Note that this excludes''
,null
,false
, and0