Checking for multiple flags. I just want to know if there is another way to check for multiple flags, different from &&?
class DemoClass
{
public const MY_FLAG1 = 0b1; // 0001 // 1
public const MY_FLAG2 = 0b10; // 0010 // 2
public const MY_FLAG3 = 0b100; // 0100 // 4
public $flags;
public function __construct($flags = DemoClass::MY_FLAG1)
{
$this->flags = $flags;
if ($this->flags & DemoClass::MY_FLAG1 && $this->flags & DemoClass::MY_FLAG2) {
throw new Exception('Flags: MY_FLAG1 and MY_FLAG2 were set');
}
}
}
MY_FLAG1 | MY_FLAG2 | MY_FLAG3 = 0b111 // 0111 // 7
Flags passed to constructor MY_FLAG1 | MY_FLAG2 | MY_FLAG3 (0111).
Check if flags: MY_FLAG1 | MY_FLAG2 are set (0011).
Example :
new DemoClass(DemoClass::MY_FLAG1 | DemoClass::MY_FLAG2 | DemoClass::MY_FLAG3);
The result of $input & $mask
is a value with bits set only if they are in both $input
and $mask
.
If $mask has only one bit set, then the result will either be all zeros, or will have one bit set. This is what you are testing at the moment - all zeros is equivalent to false in the context of an if statement or boolean expression.
But think about which bit is set if it matches - the same bit that is set in $mask, and only that bit. So the result of a successful match will be equal to $mask.
If both $input and $mask have more than one bit set, checking for zero only proves that at least one bit in $mask is also in $input. But the only way for it to match $mask is if all the bits set in $mask are also set in $input.
So if you construct a mask with all the bits you want set, you can test ($input & $mask) === $mask
In your example:
$mask = DemoClass::MY_FLAG1 | DemoClass::MY_FLAG2;
if (($this->flags & $mask) === $mask) {
throw new Exception('Flags: MY_FLAG1 and MY_FLAG2 were set');
}