PHP Null coalescing operator usage [duplicate] - php

This question already has answers here:
Is there a "nullsafe operator" in PHP?
(3 answers)
Closed 3 months ago.
Having this example code using the tertiary operator in PHP, I get the 'default value'.
$myObject = null; // I'm doing this for the example
$result = $myObject ? $myObject->path() : 'default value';
However, when I try to use the null coalescing operator to do this, I get the error
Call to a member function path() on null
$result = $myObject->path() ?? 'default value';
What am I doing wrong with the ?? operator?

?? will work if the left hand side is null or not set, however in your case the left hand cannot be evaluated if $myObject is null.
What you should consider in your case is the new nullsafe operator available with PHP 8 (so need to wait on that)
$result = $myObject?->path() ?? 'default value';
This should make the left hand side null if $myObject is null
Until then you can just do:
$result = ($myObject ? $myObject->path() : null) ?? 'default value';
This differs from your first use case in that you get default value if either $myObject or $myObject->path() are null

These snippets do not work in the same way:
$result = $myObject ? $myObject->path() : 'default value'; says: use 'default value' if $myObject is NULL
$result = $myObject->path() ?? 'default value'; says: use the default if $myObject->path() returns NULL - but that call can only return something if the object itself is not NULL

Related

Difference Between null coalescing operator (??) and nullsafe operator (?->) introduced in PHP 8

I can use ?? operator in PHP to handle an index of array which is not defined.
I am confused if null safe operator offers me same or extends ?? operator's functionality?
Edit:
I can do in existing PHP versions to check if there is a specific property is defined in the array:
$user_actions = ['work' => 'SEO','play' => 'Chess', 'drink' => 'coffee'];
$fourth_tag = $user_tags['eat'] ?? "n/a";
I am trying to understand whether null safe operator is offering me something better to do so?
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.

How does this operator '??' work in php code.? [duplicate]

This question already has answers here:
Reference Guide: What does this symbol mean in PHP? (PHP Syntax)
(24 answers)
Closed 6 years ago.
$array = ['name'=>'Jonh', 'lastname' => 'Doe', 'nickname' => 'JD'] ;
$person = $array['name'] ?? null ; //try to change null to true or false<br>
echo $person;
$person = $array['age'] ?? null; //no Undefined index: age<br>
echo $person;
I can't find any documentation about it.
It's new PHP7 "null coalescing operator":
// Fetches the value of $_GET['user'] and returns 'nobody'
// if it does not exist.
$username = $_GET['user'] ?? 'nobody';
// This is equivalent to:
$username = isset($_GET['user']) ? $_GET['user'] : 'nobody';
While
short form of Ternary Operator ?: does nearly the same for years (as of at least PHP 5.3)
You can find doc about it in php.net here.
EDIT:
It works like combination of isset() and ?
So code like:
return isset($a)?$a:$b
could be something like:
return $a??$b
This is a null coalescing operator- Please refer to this link

Is there a "nullsafe operator" in PHP?

Is there any way to write the following statement using some kind of safe navigation operator?
echo $data->getMyObject() != null ? $data->getMyObject()->getName() : '';
So that it looks like this:
echo $data->getMyObject()?->getName();
From PHP 8, you are able to use the null safe operator which combined with the null coalescing operator allows you to write code like:
echo $data->getMyObject()?->getName() ?? '';
By using ?-> instead of -> the chain of operators is terminated and the result will be null.
The operators that "look inside an object" are considered part of the chain.
Array access ([])
Property access (->)
Nullsafe property access (?->)
Static property access (::)
Method call (->)
Nullsafe method call (?->)
Static method call (::)
e.g. for the code:
$string = $data?->getObject()->getName() . " after";
if $data is null, that code would be equivalent to:
$string = null . " after";
As the string concatenation operator is not part of the 'chain' and so isn't short-circuited.
Nullsafe operator allows you to chain the calls avoiding checking whether every part of chain is not null (methods or properties of null variables).
PHP 8.0
$city = $user?->getAddress()?->city
Before PHP 8.0
$city = null;
if($user !== null) {
$address = $user->getAddress();
if($address !== null) {
$city = $address->city;
}
}
With null coalescing operator (it doesn't work with methods):
$city = null;
if($user !== null) {
$city = $user->getAddress()->city ?? null;
}
Nullsafe operator suppresses errors:
Warning: Attempt to read property "city" on null in Fatal error:
Uncaught Error: Call to a member function getAddress() on null
However it doesn't work with array keys:
$user['admin']?->getAddress()?->city //Warning: Trying to access array offset on value of type null
$user = [];
$user['admin']?->getAddress()?->city //Warning: Undefined array key "admin"
No there is not.
The absolute best way to deal with this is to design your objects in a way that they always return a known, good, defined value of a specific type.
For situations where this is absolutely not possible, you'll have to do:
$foo = $data->getMyObject();
if ($foo) {
echo $foo->getName();
}
or maybe
echo ($foo = $data->getMyObject()) ? $foo->getName() : null;

PHP variable "default value"

I want to get a value from the session, but use a default if it is not defined. And ofcourse I want to circumvent the PHP notice.
You can write a function that does this
function get(&$var, $default){
if(isset($var)) return $var;
return $default;
}
echo get($foo, "bar\n");
$foobar = "foobar";
echo get($foobar, "ERROR");
Example in action
Is there a way to do this without defining this function in every file?
You can define it in one script and then require_once that script in your other scripts
You could also just use the ternary operator:
$myVar = isset($var)?$var:$default;
From PHP 7, you can now use the null coalescing operator :
$var ?? $default
that does exactly like your function
Use this concise alternative:
isset($myVar) || $myvar=$default;
The || operator is short circuit, it will not evaluate second operant if the first one be evaluated true.
The Null coalescing operator has been added to PHP version 7.0, what it does is replaces
$username = isset($_GET['user']) ? $_GET['user'] : 'nobody';
with a shorter version:
$username = $_GET['user'] ?? 'nobody';
What the line above does, is check if $_GET['user'] is set, and not null, then it will assign that to the $username variable, if $_GET['user'] is not set (and thus null) it will default to the 'nobody' string so $username is nobody.
Your code should look like:
echo $foo ?? "bar\n";
$foobar = "foobar";
echo $foobar ?? "ERROR";
Use less code to do what you need.
You don't need to specify the variable again using the _?_:_ format.
echo $var?:"default";
Is the same as
echo $var?$var:"default";
Now as far as an empty check, you could use # to mute notices, I'm not sure of the technical ramifications, but you're already doing your own checking while using this format:
echo #$non_existing_var?:"default";
Some examples:
<?php
$nope = null;
$yup = "hello";
echo ($nope?:$yup) . "\n" ;
echo ($yup?:$nope) . "\n" ;
$items = [ 'one', 'two', false, 'three', 'four', null ];
foreach($items as $item):
echo($item?:"default shown (".var_export($item,true).")")."\n";
endforeach;
echo(#$non_existing?:"default for non-existant variable!");
?>
Output:
$ php variabledefault.php
hello
hello
one
two
default shown (false)
three
four
default shown (NULL)
default for non-existant variable!%
You could use my tiny library ValueResolver in this case, for example:
$myVar = ValueResolver::resolve($var, $default);
and don't forget to use namespace use LapaLabs\ValueResolver\Resolver\ValueResolver;
There are also ability to typecasting, for example if your variable's value should be integer, so use this:
$id = ValueResolver::toInteger('6 apples', 1); // returns 6
$id = ValueResolver::toInteger('There are no apples', 1); // returns 1 (used default value)
Check the docs for more examples

Using short circuiting to get first non-null variable

What's the equivalent of the following (based in JS style) in PHP:
echo $post['story'] || $post['message'] || $post['name'];
So if story exists then post that; or if message exist post that, etc...
It would be (PHP 5.3+):
echo $post['story'] ?: $post['message'] ?: $post['name'];
And for PHP 7:
echo $post['story'] ?? $post['message'] ?? $post['name'];
There is a one-liner for that, but it's not exactly shorter:
echo current(array_filter(array($post['story'], $post['message'], $post['name'])));
array_filter would return you all non-null entries from the list of alternatives. And current just gets the first entry from the filtered list.
Since both or and || do not return one of their operands that's not possible.
You could write a simple function for it though:
function firstset() {
$args = func_get_args();
foreach($args as $arg) {
if($arg) return $arg;
}
return $args[-1];
}
As of PHP 7, you can use the null coalescing operator:
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.
// Coalescing can be chained: this will return the first
// defined value out of $_GET['user'], $_POST['user'], and
// 'nobody'.
$username = $_GET['user'] ?? $_POST['user'] ?? 'nobody';
Building on Adam's answer, you could use the error control operator to help suppress the errors generated when the variables aren't set.
echo #$post['story'] ?: #$post['message'] ?: #$post['name'];
http://php.net/manual/en/language.operators.errorcontrol.php
You can try it
<?php
echo array_shift(array_values(array_filter($post)));
?>
That syntax would echo 1 if any of these are set and not false, and 0 if not.
Here's a one line way of doing this which works and which can be extended for any number of options:
echo isset($post['story']) ? $post['story'] : isset($post['message']) ? $post['message'] : $post['name'];
... pretty ugly though. Edit: Mario's is better than mine since it respects your chosen arbitrary order like this does, but unlike this, it doesn't keep getting uglier with each new option you add.
Because variety is the spice of life:
echo key(array_intersect(array_flip($post), array('story', 'message', 'name')));

Categories