C & PHP: Storing settings in an integer using bitwise operators? C & PHP: Storing settings in an integer using bitwise operators? php php

C & PHP: Storing settings in an integer using bitwise operators?


You sure can do it in PHP.

Let's say you have four booleans you want to store in a single value. That means we need four bits of storage space

0000

Each bit, when set individually, has a unique representation in decimal

0001 = 1 // or 2^00010 = 2 // or 2^10100 = 4 // or 2^21000 = 8 // or 2^3

A common way to implement this is with bit masks to represent each option. PHP's error levels are done this way, for example.

define( 'OPT_1', 1 );define( 'OPT_2', 2 );define( 'OPT_3', 4 );define( 'OPT_4', 8 );

Then when you have an integer that represents 0 or more of these flags, you check with with the bitwise and operator which is &

$options = bindec( '0101' );// can also be set like this// $options = OPT_1 | OPT_3;if ( $options & OPT_3 ){  // option 3 is enabled}

This operator works as such: only bits that are set in both operands are set in the result

0101 // our options0100 // the value of OPT_3----0100 // The decimal integer 4 evaluates as "true" in an expression

If we checked it against OPT_2, then the result would look like this

0101 // our options0010 // the value of OPT_2----0000 // The decimal integer 0 evaluates as "false" in an expression


It works pretty much the same way in both languages, a side by side comparison:

C:

#include <stdio.h>#include <stdint.h>#define FLAG_ONE 0x0001#define FLAG_TWO 0x0002#define FLAG_THREE 0x0004#define FLAG_FOUR 0x0008#define FLAG_ALL (FLAG_ONE|FLAG_TWO|FLAG_THREE|FLAG_FOUR)void make_waffles(void){   printf("Yummy! We Love Waffles!!!\n");}void do_something(uint32_t flags){    if (flags & FLAG_TWO)         make_waffles();}int main(void){    uint32_t flags;    flags |= FLAG_ALL;    /* Lets make some waffles! */    do_something(flags);    return 0;}

PHP:

<?phpdefine("FLAG_ONE", 0x0001);define("FLAG_TWO", 0x0002);define("FLAG_THREE", 0x0004);define("FLAG_FOUR", 0x0008);define("FLAG_ALL", FLAG_ONE|FLAG_TWO|FLAG_THREE|FLAG_FOUR);function make_waffles(){    echo 'Yummy! We Love Waffles!!!';}function do_something($flags){    if ($flags & FLAG_TWO)       make_waffles();}$flags |= FLAG_TWO;do_something($flags);?>

Note, you don't absolutely need to use constants, I just use them out of habit. Both examples will run, I compiled the C version via gcc -Wall flags.c -o flags. Change flags in either example to anything but FLAG_TWO or FLAG_ALL and (sadly) no waffles will be made.

In the C version, you don't have to tickle the preprocessor, it could quite easily be an enum, etc - that's an exercise for the reader.


quote"the idea is not good, really. you would better pass few boolean. if you want use bitwise then

function someFunc($options){   if ($options & 1 != 0)      //then option 1 enabled   if ($options & (1 << 1) != 0)      //then option 2 enabled         if ($options & (1 << 2) != 0)      //then option 3 enabled      }

"

What you have done would be okay if you were checking for a single value, although not optimal, so checking that a bit is enabled, but lets say we wanted to be able to match any, or exact we could have the following methods

function matchExact($in, $match) { // meets your criterion, as would a switch, case, but ultimately not suited for use with flags    return $in === $match;}function matchAny($in, $match) { // meets original criterion with more lexical name however it returns true if any of the flags are true    return $in |= $match;}

if you then wanted to expand upon this by having specific actions only happening if bit x,y,z was enabled then you could use the following

function matchHas($in, $match) { // more bitwise than === as allows you to conditionally branch upon specific bits being set    return $in &= $match;}

I also think if you are doing what was done in the above quote, flags may not be the best idea, exact values might be better, which does have the benefit of allowing more discreet actions. (0-255) for 8-bit over 8 distinct flags

The whole reason flags work so well is because in base 2 "8" does not contain "4", and "2" does not contain "1".

 ________________________ |8|4|2|1|Base 10 Value | ------------------------ |1|1|1|1|15            | |1|1|1|0|14            | |1|1|0|1|13            | |1|1|0|0|12            | |1|0|1|1|11            | |1|0|1|0|10            | |1|0|0|1|9             | |1|0|0|0|8             | |0|1|1|1|7             | |0|1|1|0|6             | |0|1|0|1|5             | |0|1|0|0|4             | |0|0|1|1|3             | |0|0|1|0|2             | |0|0|0|1|1             | |0|0|0|0|0             | ------------------------