Bitmasks and Bitwise Operators in PHP

Using bitmasks and bitwise operators to store, evaluate and manipulate system settings in PHP

Rod Staines
5 min readApr 16, 2023

Sometime ago I was speaking with a colleague about using bitmasks to store system flag data. He said it was a waste of time and effort.

In an employee rostering application I created, I have a timesheet feature that clients may want active only for specific employee employment types (i.e. any combination of Fulltime, Part-time, Casual, and/or Contractors).

Some developers might store each selected option as separate values (individual table columns/rows), whereas my colleague suggested I should simply store it in a single column as a string of ones and zeros with 1 representing a selected option and 0 an unselected option.

Using that approach, the above options set would be stored as 1111 and the below options set stored as 1001.

The first method is not something I wanted to pursue and the second method didn’t seem terribly efficient.

Instead of those two methods, to learn something new, I decided to investigate an alternative involving bitmasks and bitwise operators.

So, what did I learn?…

Bitmask vs Bitwise

Firstly, a bit (binary digit) is a single integer like a one or zero and a byte is a concatenation of eight bits. For example, a 6 represented in 8bit binary is 00000110.

How is that a six? Well:

  • 1 is 00000001
  • 2 is 00000010
  • 4 is 00000100
  • making 6 a combination of 2 and 4 00000110

Bitmasks and bitwise are related but distinct concepts. Bitwise operations evaluate and manipulate specific ‘bits’ within a binary representation, while a bitmask is the value representing a pattern/set of bits.

Our 00000110 above is a binary representation of 6, but it’s also a bitmask for 2 and 4.

Using Bitmasks and Bitwise Operators for Settings

Using code examples, I will demonstrate how to implement bitwise operators to create a bitmask for a single option set.

What are the bitwise operators?

PHP.net documentation lists all available bitwise operators, but for this use case, we are only concerned with the And, Or and Not operators.

https://www.php.net/manual/en/language.operators.bitwise.php

Assigning constant values

In this example, we have three classes, an Employee, TimsheetSettings and BitmaskFlags.

The Employee object will have an employment_type property and class constants for each possible employment type. Each employment type/constant is assigned an integer, double the previous.

These integers are representations of a binary value as commented.

<?php

class Employee
{
/**
* Employment type options
*/
const TYPE_CONTRACTOR = 1; // 00000001
const TYPE_CASUAL = 2; // 00000010
const TYPE_PARTTIME = 4; // 00000100
const TYPE_FULLTIME = 8; // 00001000
const TYPE_PROJECT = 16; // 00010000

}

Saving the bitmask value

The value representing the set of selected employment type options will be saved on the TimesheetSettings model against a property called import_template_for_types.

Retrieving and evaluating the bitmask

When evaluating or manipulating the setting value, create a new BitmaskFlags class and pass the current value of the setting to the constructor.

$flags = new BitmaskFlags($settings->import_template_for_types);

For the purposes of the following examples, the current stored value of import_template_for_types is 12 (only fulltime and parttime were set ON).

<?php

class BitmaskFlags {

/**
* Hold all values
*
* @var integer
*/
protected $flags;


/**
* Initialise with the current value of the flag option set
*
* @param integer $bitwise
*/
public function __construct(int $bitmask = 0)
{
$this->flags = $bitmask;
}

}

To check if a particular employment type has been set within the flags we use the & (And) bitwise operator. The & operator will evaluate to determine if the bits are set in both values (the current option set and the employment type under evaluation).

$flags->checkFlag(Employee::TYPE_FULLTIME); // true

$flags->checkFlag(Employee::TYPE_CASUAL); // false

<?php

class BitmaskFlags {

protected $flags;


/**
* Check if a particular flag is set within the flag option set
*
* @param integer $flag
* @return boolean
*/
public function checkFlag(int $flag): bool
{
return $this->flags & $flag;
}

}

Manipulating the bitmask

When you need to manipulate the bitmask to turn settings ON, use the | (Or) bitwise operator. This operator will set any bits missing from the $flags property.

$flags->setFlag(Employee::STATUS_PROJECT, true);

The $flags property will now have a value of 28 as it contains the setting value for fulltime, parttime and project.

To turn a setting OFF, use the & (And) operator in conjunction with the ~ (Not) bitwise operator. The Not operator will not include (or unset) the setting value from the $flags property.

We can use the same method for both ON and OFF, by passing a boolean state and perform a conditional bitwise operation against the $flags property.

$flags->setFlag(Employee::STATUS_PROJECT, false);

The $flags property is now back to 12.

<?php

class BitmaskFlags {

protected $flags;


/**
* Update flag option within the option set,
* using state to set whether the option is on or off
*
* @param integer $flag
* @param boolean $state
* @return integer
*/
public function setFlag(int $flag, bool $state): int
{
return $state
? $this->flags |= $flag
: $this->flags &= ~$flag;
}

}

My BitmaskFlags class also has two other methods that may be of use. A reset and a getter.

<?php

class BitmaskFlags {

protected $flags;


/**
* Get current value of flag option set
*
* @return integer
*/
public function getFlags()
{
return $this->flags;
}


/**
* Reset flag option set
*
* @return void
*/
public function reset()
{
return $this->flags = 0;
}

}

What are some other applications?

Although fun, using bitmasks and bitwise could be too “clever” or complex in a project with multiple developers. When looking at the import_template_for_types value in the database, it may not be immediately clear to a developer which options the user had selected.

I know of another application that is using bitmasks to store the status of an invoice (draft, approved, void, deleted, processing, paid, emailed etc). That’s no doubt even more confusing for developers.

Possibly more relatable, PHP itself uses bitmasks for the error_reporting php.ini setting. “To show all errors, except for notices, the php.ini file instructions say to use: E_ALL & ~E_NOTICE”.

You can read more about that on in the Bitwise Operators php.net documentation.

Want more?

Not necessarily bitwise or bitmask, but if you’d like information on counting in binary, check this page out and if you’re super geeky you might learn to count binary on your hands. My favourite is 4.

--

--