Reputation: 17566
I've just seen a video about upcoming PHP 7.4 features and saw new ??=
operator. I already know the ??
operator. How's this different?
Upvotes: 82
Views: 43024
Reputation: 963
Null Coalescing Assignment ??=
means return the value, but if it's null
then assign it a value first.
Without ??=
if ($a === null) {
$a = 1;
}
return $a;
With ??=
return $a ??= 1;
In both of the examples above:
$a
was null
, change it to 1null
is never returnedThe main use of this operator is to provide a default value in case of null.
Example use case for this Null Coalescing Assignment operator in 2024:
<?php
namespace App\Pages;
use App\Entities\User;
class WelcomePage extends AbstractPage
{
protected User $user;
protected function setUser(User $user): static
{
// assign the value (always) and then return it
return $this->user = $user;
}
protected function getUser(): User
{
// Null Coalescing Assignment:
// assign the value (only if it's null) and then return it
// else just return it
return $this->user ??= new User("Anonymous");
}
public function display(): string
{
return $this->getUser()->loggedIn() ?
"<h1>Welcome {$this->getUser()->name}! :D</h1>" :
'<h1>Welcome! :)</h1><a href="/login">log in</a>';
}
}
In this example, App\Pages\WelcomePage
is an extension of the App\Pages\AbstractPage
class which contains all of the common functions of pages in our app.
This particular page needs to get the current User
as an object and display the name, but only if logged in. This page is not responsible for managing the login state of the user - that's handled elsewhere. The getUser()
function is going to try to read the $user
property of our class, but if the property is not initialised, because we haven't called setUser()
yet, it will first initialise it with new User("Anonymous")
and then return the value of the property. Subsequent calls to getUser()
will not need to initialise the property.
We can use this WelcomePage
class later in some other file like this for anonymous users:
$page = new WelcomePage();
echo $page->display();
Or like this for logged-in users:
$page = new WelcomePage();
echo $page->setUser($loggedInUser)->display();
To extend this further, we could move $user
and its getter and setter into the AbstractPage
so that all of our pages can extend
it and have $user
initialised automatically, but only when we want to use it and not more than once.
If we didn't have this operator, we would have to rewrite this function:
protected function getUser(): User
{
if (!isset($this->user)) {
$this->user = new User("Anonymous");
}
return $this->user;
}
Or use a simple getter:
protected function getUser(): User
{
return $this->user; // can cause an error if not initialised
}
Upvotes: -2
Reputation: 3527
From the docs:
Coalesce equal or ??=operator is an assignment operator. If the left parameter is null, assigns the value of the right parameter to the left one. If the value is not null, nothing is done.
Example:
// The following 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.
Upvotes: 71
Reputation: 9926
It can roughly be translated as "$a defaults to $b", like this:
$page ??= 1; // If page is not specified, start at the beginning
$menu ??= "main"; // Default menu is the main menu
$name ??= "John Doe"; // Name not given --> use John Doe
A long-awaited tool in the world of PHP.
Before PHP 7.4, we did this with a function:
function defaultOf(&$var, $value) {
if(is_null($var)) $var=$value;
}
// Now the 3 statements above would look like:
defaultOf( $page, 1 );
defaultOf( $menu, "main" );
defaultOf( $name, "John Doe" );
(I still use it because it's more readable.)
Upvotes: 0
Reputation: 9456
You can use this to initialize variables during a loop's first iteration. But beware!
$reverse_values = array();
$array = ['a','b','c']; // with [NULL, 'b', 'c'], $first_value === 'b'
foreach($array as $key => $value) {
$first_value ??= $value; // won't be overwritten on next iteration (unless 1st value is NULL!)
$counter ??= 0; // initialize counter
$counter++;
array_unshift($reverse_values,$value);
}
// $first_value === 'a', or 'b' if first value is NULL
// $counter === 3
// $reverse_values = array('c','b','a'), or array('c','b',NULL) if first value is null
If the first value is NULL
, then $first_value
will be initialized to NULL
and then overwritten by the next non-NULL
value. If the array has a lot of NULL
values, $first_value
will end up either as NULL
or the first non-NULL
after the last NULL
. So this seems like a terrible idea.
I would still prefer doing something like this mainly because it's more clear, but also because it works with NULL
as an array value:
$reverse_values = array();
$array = ['a','b','c']; // with [NULL, 'b', 'c'], $first_value === NULL
$counter = 0;
foreach($array as $key => $value) {
$counter++;
if($counter === 1) $first_value = $value; // does work with NULL first value
array_unshift($reverse_values,$value);
}
Upvotes: 0
Reputation: 101
Null coalescing assignment operator chaining:
$a = null;
$b = null;
$c = 'c';
$a ??= $b ??= $c;
print $b; // c
print $a; // c
Upvotes: 10
Reputation: 1793
The null coalescing assignment operator is a shorthand way of assigning the result of the null coalescing operator.
An example from the official release notes:
$array['key'] ??= computeDefault();
// is roughly equivalent to
if (!isset($array['key'])) {
$array['key'] = computeDefault();
}
Upvotes: 9
Reputation: 4382
Example Docs:
$array['key'] ??= computeDefault();
// is roughly equivalent to
if (!isset($array['key'])) {
$array['key'] = computeDefault();
}
Upvotes: 3