PHP Elvis operator vs null coalescing operator
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'
.
?: operator (the 'Elvis operator') in PHP
It evaluates to the left operand if the left operand is truthy, and the right operand otherwise.
In pseudocode,
foo = bar ?: baz;
roughly resolves to
foo = bar ? bar : baz;
or
if (bar) {
foo = bar;
} else {
foo = baz;
}
with the difference that bar
will only be evaluated once.
You can also use this to do a "self-check" of foo
as demonstrated in the code example you posted:
foo = foo ?: bar;
This will assign bar
to foo
if foo
is null or falsey, else it will leave foo
unchanged.
Some more examples:
<?php
var_dump(5 ?: 0); // 5
var_dump(false ?: 0); // 0
var_dump(null ?: 'foo'); // 'foo'
var_dump(true ?: 123); // true
var_dump('rock' ?: 'roll'); // 'rock'
?>
By the way, it's called the Elvis operator.
Difference Between null coalescing operator (??) and nullsafe operator (?-) introduced in PHP 8
Null coalescing operator (??
) work as an if statement it takes two values if first is null then it is replaced by second.
$a = null;
$b = $a ?? 'B';
Here $b
will get the value B
as $a
is null
;
In PHP8, NullSafe
Operator (?->
) was introduced will gives option of chaining the call from one function to other. As per documentation here: (https://www.php.net/releases/8.0/en.php#nullsafe-operator)
Instead of null check conditions, you can now use a chain of calls with the new nullsafe operator. When the evaluation of one element in the chain fails, the execution of the entire chain aborts and the entire chain evaluates to null.
Here is the example from documentation:
$country = null;
if ($session !== null) {
$user = $session->user;
if ($user !== null) {
$address = $user->getAddress();
if ($address !== null) {
$country = $address->country;
}
}
}
But in PHP8 you can simply do this:
$country = $session?->user?->getAddress()?->country;
So the working of both operators is significantly different.
Difference between PHP ??, ?:, and ??=
To combine all answers already made in former questions. With ??
you check for existence and not being null
, with ?:
you check for true/false
.
$result = $a ?? $b
is the same as:
if (isset($a) && !is_null($a)) {
$result = $a;
} else {
$result = $b;
}
The ??=
is a shortcut for ??
and it works like .=
or +=
as well, which means you can shorten
$a = $a ?? $b;
to
$a ??= $b;
The ?:
is a shortcut for the ternary operator which is also a shortcut:
if ($a) {
$result = $a;
} else {
$result = $b;
}
is the same as:
$result = $a ? $a : $b;
is the same as:
$result = $a ?: $b;
You could both describe as: The first operand is the value to check, and if this one is useful, take it, if not, take the second as default.
You can concatenate them like this one:
$user = $_POST['user'] ?? $_SESSION['user'] ?? $_COOKIE['user'] ?? '';
Which means something like: If you get the username in the POST array because of just logging in, fine, take it, if not, see whether the user is already logged on and in the session, if yes, take it, if not, maybe we have a user in the Cookies (checked the "remember me" checkbox while last login), and if this fails also, well, then leave it empty.
Of course you have to check the password too. ;-)
Edit: I use the ?:
operator very often to ensure that I have a certain datatype in a variable. There are a lot PHP functions that give back maybe a string or an array if successful, but false
if some error occured. Instead of having false as result, having the empty string or empty array is more consistent. As example, scandir
should give back an array, but gives back false
if an error occures. So you can do this:
$files = scandir('/some/random/folder') ?: [];
Then $files
will always be an array, even if scandir
fails. Well, then it's an empty array, but maybe better than checking later against false
. In fact, we already did it with very low effort. Then you can use a foreach
loop without some wrapping if
. If scandir
failed, the array is empty and the loop will just do nothing.
What is null coalescing assignment ??= operator in PHP 7.4
From the docs:
Coalesce equal or ??=operator is an assignment operator. If the left parameter is null, assigns the value of the right paramater to the left one. If the value is not null, nothing is done.
Example:
// The folloving lines are doing the same
$this->request->data['comments']['user_id'] = $this->request->data['comments']['user_id'] ?? 'value';
// Instead of repeating variables with long names, the equal coalesce operator is used
$this->request->data['comments']['user_id'] ??= 'value';
So it's basically just a shorthand to assign a value if it hasn't been assigned before.
Using php null safe and null coalescing operators with an array containing anonymous functions
Your attempt is using the null-coalescing operator on the result of calling the function. So it won't prevent the undefined array index or calling the null function that results.
From the Nullsafe Operator RFC
Future Scope
...
A nullsafe function call syntax ($callableOrNull?()) is also outside of scope for this RFC.
So this is something that may be addressed in the future, but it's not in the existing design.
PHP Null Coalesce combined with ternary has unexpected results
hello' ?? 'a'
is truthy.
It is evaluated first.
The expression returns hello
which qualifies the printing of b
.
Ideally, developers should avoid combining multiple expressions like this for code clarity.
To avoid ambiguous multi-operator expressions, use sufficient parentheses to make things clear.
echo ('hello' ?? 'a') ? 'b' : 'c';
// which doesn't make sense because the parenthetical will always be truthy
Or
echo 'hello' ?? ('a' ? 'b' : 'c');
To explain the operator precedence page in the PHP manual, the shorthand ternary has a lower precedence/priority than the null coalescing operator. The list of operators is conveniently listed in order of precedence.
Logically, when you have a ternary expression that has an ?
(true) branch and a :
(false) branch, then it doesn't matter what is inside the leading conditional expression -- the returned values MUST be one of the branch values. In this case, the returned value can only ever be b
or c
.
The ?:
(shorthand ternary) allows the conditional evaluation's return value to be returned IF it is truthy, otherwise you get the else (falsey) branch's return value.
See:
- https://www.php.net/manual/en/language.operators.precedence.php
- https://stackoverflow.com/a/69731124/2943403
- PHP Error : Unparenthesized `a ? b : c ? d : e` is deprecated. Use either `(a ? b : c) ? d : e` or `a ? b : (c ? d : e)`
Related Topics
How to Convert Date to Timestamp in PHP
How to Send 100,000 Emails Weekly
How to Replace "If" Statement With a Ternary Operator ( : )
What in Layman'S Terms Is a Recursive Function Using PHP
How to Explain Composer'S Error Log
How to Get a Substring Between Two Strings in PHP
How to Get a File Name from a Full Path With PHP
PHP 7.2 Function Create_Function() Is Deprecated
Preferred Method to Store PHP Arrays (Json_Encode VS Serialize)
PHP Elvis Operator VS Null Coalescing Operator
Recursive Function to Generate Multidimensional Array from Database Result
Best Way to Get Result Count Before Limit Was Applied
Detecting Request Type in PHP (Get, Post, Put or Delete)
Getting Raw SQL Query String from Pdo Prepared Statements