7
\$\begingroup\$
if($row['best']){
    $id = $row['best'];
} elseif($row['average']){
    $id = $row['average'];
} elseif($row['bad']){
    $id = $row['bad'];
} 

If row['best'] is null, I need $id to equal the 2nd best. If 2nd best is null, $id is equal to the next best.

\$\endgroup\$
1
  • 10
    \$\begingroup\$ Can you add a bit of the surrounding context to your question? Where does the $row variable come from? I can imagine that there might be a possible solution where the problem can be fixed elsewhere in your code. \$\endgroup\$ Commented Mar 31, 2014 at 17:10

6 Answers 6

10
\$\begingroup\$

Simon has already answered while I was writing something similar:

foreach(array('best', 'average', 'bad') as $rank) {
  if($row[$rank]) {
    $id = $row[$rank];
    break;
  }
}

Note however, that in both this and Simon's answer, there is a possibility of $id never being assigned a value. Konijn's answer avoids that (although $id might still end up false'y)

\$\endgroup\$
2
  • \$\begingroup\$ Just assign $id the desired no-match value before the loop. \$\endgroup\$ Commented Apr 4, 2014 at 2:03
  • \$\begingroup\$ @DavidHarkness Oh sure, it's easy to handle. Just wanted to keep the code 1:1 with OP's question \$\endgroup\$
    – Flambino
    Commented Apr 4, 2014 at 8:18
10
\$\begingroup\$

How has no one mentioned the Elvis operator?!

$id = $row['best'] ?: $row['average'] ?: $row['bad'] ?: null;

Substitute your desired "not present" value of choice for null.

Edit: This is the short form of the ternary operator which evaluates to the first expression if truthy or the second expression if not. This is similar to how the || operator is often used in JavaScript.

var options = options || {};
\$\endgroup\$
3
  • \$\begingroup\$ "Elvis operator"? Never seen that one before, seems to be some ternary-operator-magic there. \$\endgroup\$ Commented Apr 2, 2014 at 11:15
  • 1
    \$\begingroup\$ Careful. If $row[xxx] doesn't exist you'll get nasty error notices. \$\endgroup\$
    – mAsT3RpEE
    Commented Apr 2, 2014 at 21:42
  • \$\begingroup\$ @mAsT3RpEE Correct, same for all of the code on this page. \$\endgroup\$ Commented Apr 3, 2014 at 8:38
5
\$\begingroup\$

You may want to write the first_in($arr, $keys) function, and rewrite your code as:

$id = first_in($row, array('best', 'average', 'bad'));

Or more common firstof($arr) function:

$id = firstof(array($row['best'], $row['average'], $row['bad'));

for example, the firstof function:

function firstof($arr) {
    foreach ($arr as $key=>$val)
       if ($val)
           return $val;
    return $arr[count($arr)-1];
}
\$\endgroup\$
4
\$\begingroup\$

From here:

If there are only 3 possibilities, you could do this:

$id = $row['best'] or $id = $row['average'] or $id = $row['bad'];

This is the closest that PHP can come to JS short circuit assignments.

\$\endgroup\$
3
  • \$\begingroup\$ I have up to 8 possibilities. For readability, I would rather use if-then-else. No? \$\endgroup\$
    – Bastien
    Commented Mar 31, 2014 at 17:41
  • \$\begingroup\$ Actually, this could still work with 8, but you would need some newlines, or, you could use @Flambino's approach which is still better than if-then-else \$\endgroup\$
    – konijn
    Commented Mar 31, 2014 at 17:44
  • \$\begingroup\$ @Bastien Oh, with 8 possibilities I would definitely use one of the iteration methods. You should update your question to reflect this requirement. Programmers tend to be literal creatures at heart. :) \$\endgroup\$ Commented Apr 4, 2014 at 1:59
4
\$\begingroup\$

There are some different approaches possible here, one of them is to use an array:

$arr = array($row['best'], $row['average'], $row['bad']);
for ($arr as $value) {
    if ($value) {
       $id = $value;
       break;
    }
}

If you consider this as a better way or not to do what you are trying to accomplish, is really up to you. I can imagine that if the possible options will be extended, then this would be really helpful. But for only three items, your current way is not that bad.

\$\endgroup\$
2
\$\begingroup\$

Maybe use array functions a bit?

$keys = array_keys($row, TRUE); // returns all keys for which value is boolean TRUE
$id = $keys[0]; // takes first one as ID

Note that this assume only one of the values is set to true or that keys are ordered from the one you want to get the most to one you want the least. It's often a safe assumption, but assumption none the less. Thus, my code is not an universal replacement of your original code, but in many real-life situations it would be pretty good - and it frees you from duplicating lists of possible keys in different parts of the script.

\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.