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

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 : [];

Related

PHP Nested object check if exist [duplicate]

This question already has answers here:
Is there a "nullsafe operator" in PHP?
(3 answers)
Closed 2 years ago.
I would like to omit checks for null in chained statements like
if($a && $a->$b && $a->$b->$c){
$d = $a->$b->$c;
}
and use optional chaining instead.
Is this possible or implemented in PHP?
Not until PHP 8.0.
This has been voted on and passed in the Nullsafe operator RFC.
The syntax will be ?->.
So the statement:
if ($a && $a->$b && $a->$b->$c) {
$d = $a->$b->$c;
}
Could be rewritten to:
$d = $a?->$b?->$c; // If you are happy to assign null to $d upon failure
Or:
if ($a?->$b?->$c) {
$d = $a->$b->$c; // If you want to keep it exactly per the previous statement
}
The Nullsafe operator works for both properties and methods.
According to this article
"The null coalescing operator ( introduced in PHP 7) is represented like this ?? used to check if the value is set or null, or in other words, if the value exists and not null, then it returns the first operand, otherwise, it returns the second operand."
So you can easily do
$d = $a->$b->$c ?? 'DEFAULT' ;
EDIT: This only works for properties, not methods (as pointed out by "hackel" in the comments below)
In PHP versions less than 8, optional chaining isn't supported. You can emulate it for properties by using the error control operator (#) which will suppress any errors that would normally occur from the assignment. For example:
$b = 'b';
$c = 'c';
$e = 'e';
$a = (object)['b' => (object)['e' => 2]];
#$d = $a->$b->$c;
var_dump($d);
#$d = $a->$b->$e;
var_dump($d);
Output:
NULL
int(2)
Demo on 3v4l.org
A better solution is to use the null coalescing operator as described in #FouedMOUSSI answer.
As of PHP8 (released 2020-11-26) optional chaining is supported via the nullsafe operator (see #Paul answer or the posted duplicate).
As mentioned by #Paul the nullsafe is available in PHP 8.
After reading this question today I just realized PHP 8 was released yesterday (2020-11-26) with nullsafe operators available :)
So yes it is available in PHP now and I can't wait to use it.
https://www.php.net/releases/8.0/en.php

Is there optional chaining in PHP? [duplicate]

This question already has answers here:
Is there a "nullsafe operator" in PHP?
(3 answers)
Closed 2 years ago.
I would like to omit checks for null in chained statements like
if($a && $a->$b && $a->$b->$c){
$d = $a->$b->$c;
}
and use optional chaining instead.
Is this possible or implemented in PHP?
Not until PHP 8.0.
This has been voted on and passed in the Nullsafe operator RFC.
The syntax will be ?->.
So the statement:
if ($a && $a->$b && $a->$b->$c) {
$d = $a->$b->$c;
}
Could be rewritten to:
$d = $a?->$b?->$c; // If you are happy to assign null to $d upon failure
Or:
if ($a?->$b?->$c) {
$d = $a->$b->$c; // If you want to keep it exactly per the previous statement
}
The Nullsafe operator works for both properties and methods.
According to this article
"The null coalescing operator ( introduced in PHP 7) is represented like this ?? used to check if the value is set or null, or in other words, if the value exists and not null, then it returns the first operand, otherwise, it returns the second operand."
So you can easily do
$d = $a->$b->$c ?? 'DEFAULT' ;
EDIT: This only works for properties, not methods (as pointed out by "hackel" in the comments below)
In PHP versions less than 8, optional chaining isn't supported. You can emulate it for properties by using the error control operator (#) which will suppress any errors that would normally occur from the assignment. For example:
$b = 'b';
$c = 'c';
$e = 'e';
$a = (object)['b' => (object)['e' => 2]];
#$d = $a->$b->$c;
var_dump($d);
#$d = $a->$b->$e;
var_dump($d);
Output:
NULL
int(2)
Demo on 3v4l.org
A better solution is to use the null coalescing operator as described in #FouedMOUSSI answer.
As of PHP8 (released 2020-11-26) optional chaining is supported via the nullsafe operator (see #Paul answer or the posted duplicate).
As mentioned by #Paul the nullsafe is available in PHP 8.
After reading this question today I just realized PHP 8 was released yesterday (2020-11-26) with nullsafe operators available :)
So yes it is available in PHP now and I can't wait to use it.
https://www.php.net/releases/8.0/en.php

Is it possible to do this with null coalescing operator?

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.

What does double question mark (??) operator mean in PHP [duplicate]

This question already has answers here:
PHP short-ternary ("Elvis") operator vs null coalescing operator
(15 answers)
Closed 4 years ago.
The community reviewed whether to reopen this question 4 months ago and left it closed:
Original close reason(s) were not resolved
I was diving into Symfony framework (version 4) code and found this piece of code:
$env = $_SERVER['APP_ENV'] ?? 'dev';
I'm not sure what this actually does but I imagine that it expands to something like:
$env = $_SERVER['APP_ENV'] != null ? $_SERVER['APP_ENV'] : 'dev';
Or maybe:
$env = isset($_SERVER['APP_ENV']) ? $_SERVER['APP_ENV'] : 'dev';
Does someone have any precision about the subject?
It's the "null coalescing operator", added in php 7.0. The definition of how it works is:
It returns its first operand if it exists and is not NULL; otherwise it returns its second operand.
So it's actually just isset() in a handy operator.
Those two are equivalent1:
$foo = $bar ?? 'something';
$foo = isset($bar) ? $bar : 'something';
Documentation: http://php.net/manual/en/language.operators.comparison.php#language.operators.comparison.coalesce
In the list of new PHP7 features: http://php.net/manual/en/migration70.new-features.php#migration70.new-features.null-coalesce-op
And original RFC https://wiki.php.net/rfc/isset_ternary
EDIT: As this answer gets a lot of views, little clarification:
1There is a difference: In case of ??, the first expression is evaluated only once, as opposed to ? :, where the expression is first evaluated in the condition section, then the second time in the "answer" section.
$myVar = $someVar ?? 42;
Is equivalent to :
$myVar = isset($someVar) ? $someVar : 42;
For constants, the behaviour is the same when using a constant that already exists :
define("FOO", "bar");
define("BAR", null);
$MyVar = FOO ?? "42";
$MyVar2 = BAR ?? "42";
echo $MyVar . PHP_EOL; // bar
echo $MyVar2 . PHP_EOL; // 42
However, for constants that don't exist, this is different :
$MyVar3 = IDONTEXIST ?? "42"; // Raises a warning
echo $MyVar3 . PHP_EOL; // IDONTEXIST
Warning: Use of undefined constant IDONTEXIST - assumed 'IDONTEXIST' (this will throw an Error in a future version of PHP)
Php will convert the non-existing constant to a string.
You can use constant("ConstantName") that returns the value of the constant or null if the constant doesn't exist, but it will still raise a warning. You can prepended the function with the error control operator # to ignore the warning message :
$myVar = #constant("IDONTEXIST") ?? "42"; // No warning displayed anymore
echo $myVar . PHP_EOL; // 42
$x = $y ?? 'dev'
is short hand for x = y if y is set, otherwise x = 'dev'
There is also
$x = $y =="SOMETHING" ? 10 : 20
meaning if y equals 'SOMETHING' then x = 10, otherwise x = 20

Why PHP isset and Null coalescing operator is throwing Notice with concatenation operator?

I have read that PHP isset and null coalescing operator used to ignore PHP Notice: Undefined index:
I have seen this post also
PHP ternary operator vs null coalescing operator
But I am getting PHP notice with both of them while using them with string concatenation operator:
<?php
$array = ['a'=>'d'];
$c = $array['c'] ?? '';
$d = isset($array['c']) ? $array['c'] : '';
$val = "sgadjgjsd".$array['c'] ?? ''; // PHP Notice: Undefined index: c in /home/cg/root/986045/main.php on line 6
$val2 = "sgadjgjsd".isset($array['c']) ? $array['c'] : ''; // PHP Notice: Undefined index: c in /home/cg/root/986045/main.php on line 7
?>
EDIT:
I know This can be solved by the following methods
1) assigning to variable like
$val = "sgadjgjsd".$c = $array['c'] ?? '';
2) using #
$val = "sgadjgjsd".#$array['c'] ?? '';
3) adding brackets (and as Karsten suggested )
$val = "sgadjgjsd".($array['c'] ?? '');
But I am looking for the reason behind it.
Every operator has its own 'importance' (operator precedence, as #Karsten-koop pointed out) which dictates in what order they are executed. For example:
echo 10 + 5 * 3; // 25 (10+15), not 45 (15×3)
In this case:
$val = "sgadjgjsd".$array['c'] ?? '';
PHP will do the following steps:
Concatenate (.) the string sgadjgjsd with the value of $array['c'].
$array['c'] does not exist, so a notice is emitted.
The end result (sgadjgjsd) is then run through the null coalescing operator, and since the string is not equal to null, the string is returned (not '').
The end result is assigned to a variable named $val.
So why does 10 + 5 * 3 equal 25? Look up the * and + operators in the table on the linked page. Notice that * is higher up in the list, so it goes first.
For the other example, the concatenation opereator . is (quite a bit) higher up than ??.
Using brackets is the proper solution; they allow you to specify what goes first:
echo (10 + 5) * 3;
$val = "sgadjgjsd".($array['c'] ?? '');
// Does ?? first and returns either the value of $array['c'] or ''
// and only then it does the string concatenation and assignment to $val.
http://php.net/manual/en/language.operators.precedence.php
Side-note: You might recognise this same concept from school because the same thing exists in mathematics (some historical background on why).
This is because you want to concatenate a string with a null in first case and in second case with boolean value
$val = $array['c'] ?? '';
will not gonna throw any error but concatenating total different data type with different one will throw error.

Categories