Class flags with bitwise operators

bitwise operatorsThere is a group of  PHP features that most of developers don’t usually use: bitwise operators.

These operators are widely used in the C language to make low-level applications (device drivers, protocols etc..). They are very useful when used in OOP developing as a flags for options in functions, classes and general settings.

Brief overview

There are 6 bitwise operators in PHP: And (&), Or (|), Xor (^), not (~), shift left(<<) and right(>>). I won’t to explain here their semantic as it’s not the purpose of this post, read the official documentation [link] if you don’t know how the bitwise operator work.

Use of as a flags : error_reporting

When an array of N binary (on/off) options is needed, the idea is using bitwise operators to store all the options within one integer value, that is a string (or array or word) of bits.
Normally, N constants are set to the values 1,2,4,8, … ,2^(N-1) so that with bitwise operator it’s possible to combine them and obtain any possible configuration of the string.

An outstanding example is the error_reporting setting in php.ini that uses 16 built-in costants (E_ERROR, E_WARNING,… E_ALL) to set its value.

E_ALL     = 000000000000001 #int: 1
E_WARNING = 000000000000010 #int: 2
E_PARSE   = 000000000000100 #int: 4
E_NOTICE  = 000000000001000 #int: 8
...
E_STRICT  = 000100000000000 #int: 2048
...
E_ALL     = 111011111111111 #int: 30719

Here are some examples to obtain some configurations:

  • The Or(|) operator can be used to “add” options:
    E_ERROR | E_WARNING | E_PARSE = 000000000000111
  • The And(&) and Not(~) operator can be used as a “subtraction“. Example: E_ALL (all the options) except E_NOTICE:
    E_ALL & ~E_NOTICE = 111011111110111 = (see the values above, note the last but three bit )
  • You can use also Xor (^), for example to obtain the same as above
    E_ALL & ~E_NOTICE = E_ALL ^ E_NOTICE

Create your flags in your class

Let’s implement a class with some constants used as a flag and a method that is able to read each option. That is a better alternative than using 4 different fields and methods to set the options.

We’ll use the operator And (&) betwen the option value and the entire string to check if the options is set. Indeed, the result of that operator is a string with each bit set to 1 if both bits in the same position are set to 1. So, if the result is a string with at least one bit, it means that the option is enabled.

Have a look at the following class with 4 options and its usage

class MyClass {
 const OP1 = 1;   // 001
 const OP2 = 2;   // 010
 const OP3 = 4;   // 100
 const OPALL = 7; //111

 public static function foo($option) {
  if ($option & self::OP1){ echo "OP1 enabled - ";}
  if ($option & self::OP2){ echo "OP2 enabled - ";}
  if ($option & self::OP3){ echo "OP3 enabled - ";}
  echo "n";
 }

}

// enable the 1st option
MyClass::foo(MyClass::OP1);

// enable the 1st and 2nd option
MyClass::foo(MyClass::OP1|MyClass::OP2); #001 | 010 = 011

// enable all the options, equivalent to MyClass::OP1|MyClass::OP2|MyClass::OP3
MyClass::foo(MyClass::OPALL);

// enable all the options except options3
MyClass::foo(MyClass::OPALL & ~MyClass::OP3); # 111 & ~100 = 111 & 011 = 011

// equivalent with Xor
MyClass::foo(MyClass::OPALL ^ MyClass::OP3); # 111 ^ 100 = 011