TryHarder
TryHarder

Reputation: 2777

What is a shorthand way for checking that multiple variables are ALL equal to the same value in an IF statement? (PHP)

Is there a shorthand way of writing the code below?

if (($tstat=='no_prices')&&($l1stat=='no_prices')&&($l2stat=='no_prices')&&($l3stat=='no_prices'))
{                                   
    //do something
}

I tried using the below code,but it did something when one of the variables was not equal to 'no_prices'.

if (($tstat && $l1stat && $l2stat && $l3stat)=='no_prices')
{
    //do something
}

To check that the strings weren't causing problems I tried substituting 0 for 'no_prices' and 1 for other values, but the result was the same.

Upvotes: 17

Views: 3982

Answers (8)

Markus Malkusch
Markus Malkusch

Reputation: 7868

My first idea would go into PHP's Array API:

// $tstadt, $l1stat, … are all "no_prices"
$isAllNoPrice = array_unique(array($tstat, $l1stat, …)) == array("no_prices"));
if ($isAllNoPrice) {
    // …

}

Documentation is mandatory otherwise nobody (including yourself) will understand the code.

If efficiency might be a concern others pointed out that array_unique() seems to be slow. Using the keys of the hash table would be a next approach:

// $tstadt, $l1stat, … are all "no_prices"
$varsMap = array(
    $tstat  => null,
    $l1stat => null,
    // …
);
if (array_keys($varsMap) == array("no_prices")) {
    // …

}

But now the wall of code is growing. PHP offers one operator which nearly does what you want and is chainable: &

$v1 = "no_prices";
$v2 = "no_prices";
$v3 = "no_prices";

var_dump(($v1 & $v2 & $v3) == "no_prices"); // bool(true)

$v3 = "prices";
var_dump(($v1 & $v2 & $v3) == "no_prices"); // bool(false)

I said it nearly does what you want: There are cases in which you will have false positives:

$v1 = 1;
$v2 = 1;
$v3 = 3;

var_dump(($v1 & $v2 & $v3) == 1); // bool(true)

For Strings it seems to cut the bitmask to the shortest string:

$v1 = "abcd";
$v2 = "ab";
$v3 = "abc";

var_dump($v1 & $v2 & $v3); // "ab"
var_dump(($v1 & $v2 & $v3) == "ab"); // bool(true)

So I don't recommend this as a general purpose solution. Only if you know (=unit tested) that your values are in a set where no combination never results to a false positive (e.g. {"dog", "cat", "horse"}) you might consider this solution. I gave it a second thought and must say don't use that at all. Imagine how your colleagues will love you for searching a bug introduced by that method.

Upvotes: 7

primo
primo

Reputation: 1454

array_flip is several times faster than array_unique:

function all_equal($arr, $value) {
  return array_keys(array_flip($arr)) == array($value);
}

$arr = array($tstat, $l1stat, $l2stat, $l3stat);

echo all_equal($arr, 'no_prices');

A quick profile for the answers given thus far, for 1000 iterations on array length 1000:

  array_flip: 0.07321620 seconds
array_unique: 0.32569408 seconds
     foreach: 0.15136194 seconds
array_filter: 0.41404295 seconds

The code used to profile is here: http://codepad.org/szgNfWHe

Note: As @cypherabe rightly points out, array_flip does not overtake array_unique until the array has at least 5 elements, and does not overtake foreach until the array has at least 10 elements.

Upvotes: 22

Steve Clay
Steve Clay

Reputation: 8781

The answer is "no". There's no shorthand to the given condition that will make your code more readable, which should be your top priority. You can improve it though:

define('MYAPP_NO_PRICES', 'no_prices');

if ($tstat === MYAPP_NO_PRICES
        && $l1stat === MYAPP_NO_PRICES
        && $l2stat === MYAPP_NO_PRICES
        && $l3stat === MYAPP_NO_PRICES) {                                 
    // do something
}

Having all these vars to check individually is a code smell; you might want to rethink this design so you never have to do this.

Upvotes: 0

Bez Hermoso
Bez Hermoso

Reputation: 1132

In your case you can do:

if (count(array_unique($tstat, $l1stat, $l2stat, $l3stat)) == 1 //Check if all share the same value (i.e., number of unique values is 1
&& $tstat == 'no_prices')) //If everything is the same and $stat == 'no_prices', then everything is 'no_prices'
{

}

Upvotes: 4

Awlad Liton
Awlad Liton

Reputation: 9351

try this:

$arr = array($tstat,$l1stat,...); //make an array
$arr =array_unique($arr);//unique this array

if(count($arr) == 1 && $arr[0] = 'no_prices'){ // check if only one array element have with same value
    echo "got it";
}

demo example

Upvotes: 2

DhruvPathak
DhruvPathak

Reputation: 43235

<?php
$tstat = $l1stat = $l2stat = $l3stat = 'no_prices';
$testVars = array($tstat,$l1stat,$l2stat,$l3stat);

if(count(array_filter($testVars, function($x) { return $x === 'no_prices'; })) == count($testVars))
{
        print("Correct");
}

Use array_filter with a anonymous callback, and check if its length is greater is equal to original array i.e. all conditions passed,

or if length is greater than zero i.e. any one condition passed

Upvotes: 3

aksu
aksu

Reputation: 5235

No, this code won't work:

if (($tstat&&$l1stat&&$l2stat&&$l3stat)=='no_prices')
{
    //do something
}

Why? Because condition in parentheses, will check result itself - You are comparing boolean to string. So in pseudo-code, thats what your code looks like:

if ( ($tstat is true, $l1stat is true, $l2stat is true, $l3stat is true) == 'no_prices' )
     ^                         whole thing returns true                ^    ^   true  ^

If you wan't to achieve this, you can use count() and array_unique():

if ($tstat == 'no_prices' && count(array_unique(array($tstat, $l1stat, $l2stat, $l3stat))) == 1)

Upvotes: 2

Flosi
Flosi

Reputation: 671

Unless I'm mistaken, there's no native way of doing this. If this is something that you have to check for often, try using a custom function for it, e.g.:

function allEquals($chkstr, $vals) {
    if (!is_array($vals)) { die('allEquals() $vals not an array'); }
    foreach ($vals AS $v) {
        if ($chkstr != $v) { return false; }
    }
    return true;
}

Upvotes: 9

Related Questions