How to avoid undefined index warning for chains of 'default' values? - php

Let's say I want to check for a couple of different parameters, and then fall back to a default value, is there a way to do it without ugly and verbose writing of isset()?
For example in JS we can do:
var someVariable = otherVar || anotherVar || 'fallback here';
The equivalent in PHP would be something like:
$someVariable = (isset($otherVar) ? $otherVar : (isset($anotherVar) ? $anotherVar : 'fallback here'));
which is obviously a mess and horrible to read.
Lots of solutions exist for single fallbacks, i.e.:
$someVariable = $otherVar ?: 'fallback here';
but that doesn't help me with requiring more than one in the line of checks.
Given that I am only interested in whether or not the value is set or truth-y (i.e. I am happy for 1 to be accepted as the used value, and for 0/false/null to be skipped and for the next parameter in the chain to be used), what is the best way to avoid the undefined index warning?
In reality, I would be doing this on arrays in most cases, but not all, and it's probably that they will be different arrays. I may want to use $_POST for the first, then check $_GET under a different key, and then fall back to a default string for example.

Ignoring PHP warnings and notices is not a good idea at all.
But just for the experiment, I can suggest you the error control operator #.
PHP supports one error control operator: the at sign (#). When prepended to an expression in PHP, any error messages that might be generated by that expression will be ignored.
$someVariable = #$otherVar ? #$var : 'fallback here';
echo $someVariable;
// output: fallback here
http://php.net/manual/en/language.operators.errorcontrol.php

You can chain ?: but you'll still need to suppress errors with #.
For example, the following will work similarly to your JavaScript example:
$foo = #$bar ?: #$baz ?: #$qux ?: "I give up";
It's the equivalent of multiple "single fallbacks":
$foo = (#$bar ?: (#$baz ?: (#$qux ?: "I give up")));
Be careful though, ?: only checks for truthyness. There are scenarios where isset() and truthyness do not agree. Additionally, ?: fallback functionality was introduced in PHP 5.3.
If you only care about nullness and have PHP 7 available, it introduced a null coalescing operator.

This is ambiguous and it is deprecated...
$something = $a ? $b : $c ?: $d;
So, you have 2 alternatives for grouping:
$something = $a ? $b : ($c ?: $d); // version 1
$something = ($a ? $b : $c) ?: $d; // version 2
Which one is correct? Let's test this...
$posibilities = [TRUE, FALSE, NULL, [], new stdClass()];
$v1_is_correct = TRUE;
$v2_is_correct = TRUE;
foreach ($posibilities as $a) {
foreach ($posibilities as $b) {
foreach ($posibilities as $c) {
foreach ($posibilities as $d) {
$original = (int)($a ? $b : $c ?: $d);
$v1 = (int)($a ? $b : ($c ?: $d));
$v2 = (int)(($a ? $b : $c) ?: $d);
$v1_is_correct = $v1_is_correct && ($original === $v1);
$v2_is_correct = $v2_is_correct && ($original === $v2);
print "ORIG: $original - V1: $v1 - V2: $v2 \n";
}
}
}
}
print "\n";
$v1_is_correct ? print "V1 is correct \n" : NULL;
$v2_is_correct ? print "V2 is correct \n" : NULL;
Result: V2 is correct.
$a ? $b : $c ?: $d
is equivalent to...
($a ? $b : $c) ?: $d

Related

PHP or shorthand for empty variable

$a = '';
$b = 1;
How to print $b if $a = '' using shorthand in PHP?
in javascript there is something like
a || b;
Ternary Operator
$a = '';
$b = 1;
echo $a ?: $b; // 1
Until $a is evaluated false, $b will be displayed. Remember that the following things are considered to be empty:
"" (an empty string)
0 (0 as an integer)
0.0 (0 as a float)
"0" (0 as a string)
NULL
FALSE
array() (an empty array)
$var; (a variable declared, but without a value)
That means that if $a is "", 0, "0", null, false, array(), .. then $b will be displayed. See PHP type comparison tables.
If you want to display $b only when $a is an empty string, then you should uses strict comparison operators (===)
$a = '';
$b = 1;
echo $a === '' ? $b : ''; // 1
This is the shorthand for an IF/Else statement in PHP.
echo ($a != '' ? $a : $b)
If $a is not an empty string output (echo) $a otherwise output $b.
As others ahve said Turnary operator is handy for most senarios.
echo $a ?: $b;//b
But it is NOT shorthand for empty().
Ternary operator will issue notices if var/array keys/properties are not set.
echo $someArray['key that doesnt exist'] ?: $b;//Notice: Undefined index
echo $arrayThatDoesntExist['key-that-doesnt-exist'] ?: $b;//Notice: Undefined variable
empty() will take care of the additional checks for you and its recomended to just use it.
if (empty($arrayThatDoesntExist['key-that-doesnt-exist'])) echo $b;
You could technically just suppress the warning/notice with # and the ternary operator becomes a replacement for empty().
#echo $someArray['key that doesnt exist'] ?: $b;
#echo $arrayThatDoesntExist['key-that-doesnt-exist'] ?: $b;
But usually not recommended as supressing notices and warnings could lead you into trouble later on plus I think it may have some performance impact.

Setting a variable's value according to the existence of two or more variables

How can we set a variable's value according to the existence of one or more variables?
This works but I want to know if PHP has a "shorthand" version for this:
if (isset($a)) { $x=$a; } elseif (isset($b)) { $x=$b; }
In case you want the bigger picture, I need to give $x the value of $_REQUEST['a'] or $_GET['a'], whichever one exists each time.
EDIT: ternary operators will do the trick for 2 variables. Could the functionality expand for more than 2? Example
if (isset($a)) { $x=$a; } elseif (isset($b)) { $x=$b; } else { $x=$c; }
Use a ternary operator:
$x = isset($a) ? $a : $b;
I think ternary operators quickly becomes unreadable if misused. So let me suggest an alternative way of thinking:
$x=$c; // default
if (isset($b)) $x=$b;
if (isset($a)) $x=$a;
Or:
function first_set($array,$default=null){
foreach($array as $e) if isset($e) return $e;
return $default;
}
$x=first_set(array($a,$b),$c);
You may stack ternary operators:
<?php
$x = isset($a) ? $a : (isset($b) ? $b : null);
?>
Also, it might be extended to:
<?php
$x = isset($a) ? $a : (isset($b) ? $b : (isset($c) ? $c : null));
?>
NOTE: You need braces to avoid non-obvious execution.
It is recommended that you avoid "stacking" ternary expressions. PHP's
behaviour when using more than one ternary operator within a single
statement is non-obvious.
I recommend, to do not complicate such expressions too much. It might affect code readability.
You can try doing this:
$x = ($a) ?: $b; // if you are using 5.3+
$x = ($a) ? $a : $b; // if >PHP5.3
$x=isset($a)?$a:(isset($b)?$b:'default value');
You can nest as many conditions as you want.\
$x=isset($a)?$a:(isset($b)?$b:(isset($c)?$c:'other ternary condition'));

Assign variable with the aid of boolean operators

Is there some short way to do this
if (!empty($b))
$a = $b;
else if (!empty($c)) {
$a = $c;
i know you could use ternary operator but its not what i asking like in JavaScript there is way to assign like this
my_var = some_Var || fu_bar || 0;
so if first dont exist it uses second and if second dont exist it uses third one.
is there similar thing in php?
cant think of other way than this:
$a = ! empty($b) ? $b : (! empty($c) ? $c : 0)
you can use one of the two ways whatever suits you. both of these functions will check either we have the non empty variable or not.
1: $a = (isset($b) && $b)?$b:$c;
2: if($b)
$a = $b;
elseif($c)
$a = $c;

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

Fallthrough variable assignment in PHP? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Coalesce function for PHP?
I'm not sure what this is normally called, but I hope the title communicates well enough. What I have is a handful of variables some of which might be null.
I want to do:
$a = $b || $c || $d;
Where $a ends up being = to the first non-null variable.
To my knowledge, PHP doesn't support this in the same way JavaScript does.
You can, however do something like this:
$a = $b ? $b : ($c ? $c : $d);
A more general solution:
function fallthrough($arr) {
//$arr should be an array of possible values. The first non-null value is returned
do $a = array_shift($arr);
while($a === null && $arr);
return $a;
}
<?php
$a = 0;
$b = false;
$c = true; //should become this
$d = '1';
$e = $a ?: $b ?: $c ?: $d;
var_dump($e);
//bool(true)
//should be '1' if order is different
$e = $a ?: $b ?: $d ?: $c;
var_dump($e);
//string(1) "1"
... however ?: is kinda new, you will confuse your colleagues / fellow coders.
I don't think that's possible. I think you'd have to use some other, more laborious, way. I.e. make an array of the variables, iterate through it until you find a non-null value and break the loop, like so:
$vars = array("b" => $b, "c" => $c, "d" => $d);
foreach($vars as $var) {
if($var != null) {
$a = $var;
break;
}
}
Well, like some other answers here say, you can use the shorthand way of writing this, but writing readable code is important too. The above code is pretty readable.

Categories