PHP Nested object check if exist [duplicate] - php

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

Related

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

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

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

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;
}

Setting default values (conditional assignment)

In Ruby you can easily set a default value for a variable
x ||= "default"
The above statement will set the value of x to "default" if x is nil or false
Is there a similar shortcut in PHP or do I have to use the longer form:
$x = (isset($x))? $x : "default";
Are there any easier ways to handle this in PHP?
As of PHP 5.3 you can use the ternary operator while omitting the middle argument:
$x = $x ?: 'default';
As of PHP 7.0, you can also use the null coalesce operator
// PHP version < 7.0, using a standard ternary
$x = (isset($_GET['y'])) ? $_GET['y'] : 'not set';
// PHP version >= 7.0
$x = $_GET['y'] ?? 'not set';
isset($x) or $x = 'default';
As of PHP 7.4 you can write:
$x ??= "default";
This works as long as $x is null. Other "falsy" values don't count as "not set".
I wrap it in a function:
function default($value, $default) {
return $value ? $value : $default;
}
// then use it like:
$x=default($x, 'default');
Some people may not like it, but it keeps your code cleaner if you're doing a crazy function call.
I think your longer form is already the shortcut for php... and I wouldn't use it, because it is not good to read
Some notice:
In the symfony framework most of the "get"-Methods have a second parameter to define a default value...

Categories