3

Sometimes in programming they allow one to chain parameters in a single function input variable like the second input variable below:

define('FLAGA',40);
define('FLAGB',10);
define('FLAGC',3);
function foo($sFile, $vFlags) {
  // do something
}
foo('test.txt',FLAGA | FLAGB | FLAGC);

PHP calls this single pipe character (|) the Bitwise OR operator. How do I now add something inside foo() to test $vFlags to see which flags were set?

Sarat Patel
  • 856
  • 13
  • 32
Volomike
  • 23,743
  • 21
  • 113
  • 209

3 Answers3

5

I think you'll find that flags like this are normally defined as powers of 2, e.g.:

define('FLAGA',1);
define('FLAGB',2);
define('FLAGC',4); /* then 8, 16, 32, etc... */

As you rightly stated, these can be combined by using a bitwise OR operator:

foo('test.txt',FLAGA | FLAGB | FLAGC);

To test these flags inside your function, you need to use a bitwise AND operator as follows:

function foo($sFile, $vFlags) {
  if ($vFlags & FLAGA) {
    // FLAGA was set
  }
  if ($vFlags & FLAGB) {
    // FLAGB was set
  }
  //// etc...
}
r3mainer
  • 23,981
  • 3
  • 51
  • 88
3

The "flags" parameter would be called a bitmask. A single byte contains 8 bits which are either set or not set. You simply assign your own meaning to every bit; if it's set it means yes for that particular bit, otherwise no.

So you need to start by defining your flags with the correct values which set the right bits; just arbitrary numbers won't combine together in the right ways:

define('FLAGA', 1);  // 00000001
define('FLAGB', 2);  // 00000010
define('FLAGC', 4);  // 00000100
define('FLAGD', 8);  // 00001000

Given the above, FLAGB | FLAGD creates a bit mask with the second and forth bit set (00001010). You need to get somewhat comfortable with converting between base 2 (binary) and base 10 (decimal) for this.

To test for this, you use &:

$flags = FLAGB | FLAGD;

if ($flags & FLAGA) {
    echo 'flag A is set';
}

if ($flags & FLAGB) {
    echo 'flag B is set';
}

..
deceze
  • 510,633
  • 85
  • 743
  • 889
0

You need the bitwise AND operator &:

define('FLAGA',40);
define('FLAGB',10);
define('FLAGC',3);

function foo($sFile, $vFlags) {
  if ($vFlags & FLAGA) {
    echo "FLAGA is set\n";
  }
  if ($vFlags & FLAGB) {
    echo "FLAGB is set\n";
  }
  if ($vFlags & FLAGC) {
    echo "FLAGC is set\n";
  }
}
foo('test.txt',FLAGA | FLAGB | FLAGC);

DEMO

That said, bitwise operations necessarily work in terms of binary, where each bit represents a power of 2. So, you are typically going to want to define flags in powers of 2, as in

define('FLAGA',1);
define('FLAGB',2);
define('FLAGC',4);
define('FLAGD',8); // etc.

Otherwise, imagine this scenario:

define('FLAGA',8);
define('FLAGB',32);
define('FLAGC',40);

If you have a value 40 for $vFlags, you can't tell what flags are set; it could be any of the following:

FLAGA & FLAGB
FLAGA & FLAGB & FLAGC
FLAGA & FLAGC
FLAGB & FLAGC
FLAGC
elixenide
  • 44,308
  • 16
  • 74
  • 100
  • Remember type coersion in Php when unit-testing :) The evaluated value of ($vFlags & FLAGC) results either in 0 (zero) or a non-zero integer. This will evaluate the same as a boolean, but if you're unit-testing and asserting a boolean value, the assertion will fail no matter what. `$test = $vFlags & FLAGC;` `assertTrue($test) // this will fail because $test is actually an integer, not a boolean` `assertTrue($test == FLAGC) // this will work because now there is an actual boolean value` `if($test){... // this will work because of type coersion` – andkrup Feb 17 '21 at 10:42