Is it possible to do this with null coalescing operator? - php

With isset(), you can do this:
$foo = [];
$baz = [];
$bar = isset($foo['bar'], $baz[$foo['bar']]) ? $baz[$foo['bar']] : '';
Is it possible to achieve the same thing with null coalescing like:
$bar = ($foo[$bazz['foo']]) ?? ''; //Undefined variable: bazz
Im expecting $bar to be:
$bar = '';
??: Null coalescing operator

You have to use the ?? operator twice.
$foo = [];
$baz = [];
$bar = $baz[$foo['bar'] ?? ''] ?? '' ;
See it in action on 3v4l.org

When you are not sure whether a variable/array element exists, you will need to use isset to avoid errors. You can use the # operator to avoid displaying error messages, but the error will just not be displayed, it will occur nonetheless. Avoid the # operator when possible.

The simple answer to that question is that you cannot achieve the same behavior with ?? simply because the operator passes only 1 argument to isset() and you need to pass multiple ones.
The solution with # is really bad and should be avoided. So I suggest just using isset() even for code readability.

Related

Nesting null coalescing operator [duplicate]

According to PHP documentation, the null coalescing operator ?? is right-associative, i.e.
$a ?? $b ?? $c
is equivalent to
$a ?? ($b ?? $c)
What is the significance of this? Does it make any difference for developers that it is left-associative or right-associative?
To those who are thinking it will call less functions, this is not true because the right operand will not be evaluated if the left operand is not null according to my test:
function f(string $a) : string {
echo "f($a)\n";
return $a;
}
var_dump(f("a") ?? f("b") ?? f("c") ?? f("d"));
echo "===\n";
var_dump(((f("a") ?? f("b")) ?? f("c")) ?? f("d"));
Output:
f(a)
string(1) "a"
===
f(a)
string(1) "a"
I am thinking about performance issues, where you have to evaluate ?? multiple times (if the first value is non null) if it is left-associative while once only if it is right-associative. Compare these two cases:
(("a" ?? "b") ?? "c") ?? "d"
"a" ?? ("b" ?? ("c" ?? "d"))
On the first line, after the second (inner) parentheses ?? "b" is resolved, the value inside the first (outer) parentheses ?? "c" is resolved, then the final ?? "d" is resolved. ?? is performed 3 times.
On the second line, since "a" is not null, the whole chunk of ("b" ?? ("c" ?? "d")) does not need to be resolved. ?? is only performed once.
Although the right-hand-side value is not resolved, checking !== null fewer times might still be beneficial.
(Still, I wonder if this is the only reason?)
As (left) operands don't have to be defined variables (containing alternatively null i.e. undefined value) and just the most right one operand within multiple (stacked) coalesce expressions without explicit parentheses grouping should be "backup value", main effect of implicit right associativity for this case seems to be that warning(s) of undefined variable(s) is (are) prevented. So, that's correct (acceptable) to use for all left operands (except for the most right) variables that aren't (or needn't to be) defined at all.
This code without explicit grouping using parentheses, so applying implicit right associativity
$a = $b ?? $c ?? $d;
echo $a;
outputs
Warning: Undefined variable $d
since all operand variables (including the most right "backup" $d) are undefined.
However, this code with explicit grouping simulating left associativity
$a = ($b ?? $c) ?? $d;
echo $a;
outputs
Warning: Undefined variable $c
Warning: Undefined variable $d
as both (all) right operands are evaluated and considered existing "backup" value.
Check here:
https://3v4l.org/ZvTl9
https://3v4l.org/pEWk9
What is the significance of this?
Compared to the ternary operator (which is left-associative), the null coalesce operator being right-associative allows for stacking. For example:
This won't work
echo isset($foo) ? $foo :
isset($bar) ? $bar :
isset($baz) ? $baz :
'default';
This is how you might expect the ternary operator to work by default coming from C or C++, but you would be wrong. The new ?? operator allows for the following alternative:
This will work
echo $foo ?? $bar ?? $baz ?? 'default';

What is the shortest way

What are the shortest equivalents to the two following statements which do not generate a notice (when error_reporting is E_ALL):
$foo = empty($row['foo']) ? 42 : $row['foo'];
$foo = empty($row['foo']) ? null : $row['foo'];
The variable in empty() could be non existent or an empty string.
This has been bugging me for so long. I have been searching for alternatives across the Internet, including SO.
The null coalescing operator does not seem to work:
$foo = $bar ?? 42;
var_dump($foo);
returns '', not 42.
Are my examples really the shortest form to write it?
The null-coalescing operator (??) will only check for either null or undefined variables.
The shorthand ternary operator (?:) will check for falsy values but can't handle undefined variables by itself.
Therefore, the only shorter way to write these two lines would be to use a combination of both:
$foo = ($row['foo'] ?? null) ?: 42;
and:
$foo = ($row['foo'] ?? null) ?: null;
Whether this is easily readable is debatable, but that should work.

PHP - assignment by reference with null coalescing operator [duplicate]

This question already has answers here:
PHP - foreach lose reference with null coalescing operator
(3 answers)
Closed 12 months ago.
I tried to create a variable that contains the reference to another variable if defined, or an other value:
$arr = &$original ?? [];
In this example, everything is okay when $original is already defined. When it isn't, the null coalescing operator seems to be skipped as $arr contains NULL and not the default empty array.
Using a ternary operator would cause a parse error:
$arr = isset($original) ? &$original : [];
The only way to achieve this would be with a if statement which is a longer syntax:
if (isset($original)) {
$arr = &$original;
} else {
$arr = [];
}
Would there be a shorter way to achieve this ?
Why does the null coalescing operator can't help here ? Should it ?
EDIT:
It appears that the assignment by reference will create the variable if it does not exists:
$b = &$a ?? [];
var_dump($a); // without the previous line, triggers a "Notice: Undefined variable: a in ..."
But still, $a is null, and $b should contain an empty array.
You can approach this as
$arr = isset($original) ? $arr = &$original : [];

Assign variable within condition if true

I know you can assign a variable in a condition like this:
if ($var = $foo)
However I don't need to do anything in the condition itself, so I'm often left with empty brackets. Can I simply assign $var if $foo is true in some other way without needing to do something else later?
Also can I assign $var to $foo if $foo is true but if $foo is false do something else? Like:
if ($var = !$foo) {
if ($var = !$bar) {
//Etc...
}
}
Basically I want to have more fallbacks/defaults.
#chandresh_cool's suggestion is right but to allow multiple possiblities / fallbacks you would have to nest the ternary expressions:
$var = ($foo == true) ? $foo:
($bar == true) ? $bar:
($fuzz == true) ? $fuzz:
$default;
Note: the first 3 lines end in colons not semi-colons.
However a simpler solution is to do the following:
$var = ($foo||$bar||$fuzz...);
Although this is a very old post. Fallback logic on falsify values can be coded like this.
$var = $foo ?: $bar ?: "default";
In this case when $foo is a falsified value (like false, empty string, etc.) it will fall back to $bar otherwise it uses $foo.
If bar is a falsified value, it will fallback to the string default.
Keep in mind, that this works with falsified values, and not only true.
example:
$foo = "";
$bar = null;
$var = $foo ?: $bar ?: "default";
$var will contain the text default because empty strings and null are considered "false" values.
[update]
In php 7 you can use the new null coalescing operator: ??, which also checks if the variable exists with isset(). This is usefull for when you are using a key in an array.
Example:
$array = [];
$bar = null;
$var = $array['foo'] ?? $bar ?? "default";
Before php 7 this would have given an Undefined index: foo notice. But with the null coalescing operator, that notice won't come up.
Instead you can Use ternary operator like this
$var = ($foo == true)?$foo:"put here what you want";
You can assign values like this:
$var = $foo;
Setting them within an if statement is also possible, PHP will evaluate the resulting $var which you just assigned.
I dont really get your question, but you could do something like this:
if(!($var = $foo)){
//something else.
}

Assign if variable is set

In PHP I find myself writing code like this frequently:
$a = isset($the->very->long->variable[$index])
? $the->very->long->variable[$index]
: null;
Is there a simpler way to do this? Preferably one that doesn't require me to write $the->very->long->variable[$index] twice.
An update, because PHP 7 is now out and is a game-changer on this point ; the previous answers are about PHP 5.
PHP 7 solves this issue. Because you are true at saying that it is frequent to write this in PHP, and that's absolutely not elegant.
In PHP 7 comes the Null Coalesce Operator (RFC), which is a perfect shorthand for the isset ternary condition.
Its goal is to replace this type of condition:
$var = isset($dict['optional']) ? $dict['optional'] : 'fallback';
By that:
$var = $dict['optional'] ?? 'fallback';
Even better, the null coalesce operators are chainable:
$x = null;
# $y = null; (undefined)
$z = 'fallback';
# PHP 7
echo $x ?? $y ?? $z #=> "fallback"
# PHP 5
echo isset($x) ? $x : (isset($y) ? $y : $z)
The null coalesce operator acts exactly like isset() : the subject variable's value is taken if:
The variable is defined (it exists)
The variable is not null
Just a note for PHP beginners: if you use the ternary condition but you know that the subject variable is necessarily defined (but you want a fallback for falsy values), there's the Elvis operator:
$var = $dict['optional'] ?: 'fallback';
With the Elvis operator, if $dict['optional'] is an invalid offset or $dict is undefined, you'll get a E_NOTICE warning (PHP 5 & 7). That's why, in PHP 5, people are using the hideous isset a ? a : b form when they're not sure about the input.
Sadly no, because the RFC has been declined. And because isset is not a function but a language construct you cannot write your own function for this case.
Note: Because this is a language construct and not a function, it cannot be called using variable functions.
If you only assign null instead of the non set variable, you can use:
$a = #$the->very->long->variable[$index];
# makes that instruction throw no errors
Assuming you know that $the->very->long->variable is set, and you're just worried about the array index....
$x = $the->very->long->variable;
$a = isset($x[$index]) ? $x[$index] : null;
Or for a more generic variant that you can use around you code:
function array_valifset($arr,$k, $default=null) {
return isset($arr[$k]) ? $arr[$k] : $default;
}
then call it like this for any array value:
$a = array_valifset($the->very->long->variable,$index);
I stumbled across the same problem and discovered that referencing an array element does not issue a notice or warning but returns null (at least PHP 5.6).
$foo = ['bar' => 1];
var_dump($bar = &$foo['bar']); // int 1
var_dump($baz = &$foo['baz']); // null
Inside an if statement:
if($bar = &$foo['bar']) {
echo $bar;
}
if($baz = &$foo['baz']) {
echo $baz;
}

Categories