PHP Elvis Operator VS Null Coalescing Operator

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.

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



Leave a reply



Submit