patternphpMinor
PHP Bitmask class
Viewed 0 times
phpclassbitmask
Problem
I have been trying to learn more about using bits/bitfields/bitmask or whatever you call them exactly in PHP for different settings and permissions. With the help of others, I have come up with this class. It has come a long way from when I started it but I am looking for any ideas on how to improve it more.
Example usage:
value = $value;
}
public function getValue() {
return $this->value;
}
public function get($n) {
if (is_int($n)) {
return ($this->value & (1 value = ($this->value & ~(1 set($n, false);
}
}
class UserPermissions_BitField extends BitField
{
const PERM_READ = 0;
const PERM_WRITE = 1;
const PERM_ADMIN = 2;
const PERM_ADMIN2 = 3;
const PERM_ADMIN3 = 4;
}
class UserPrivacySettings_BitField extends BitField
{
const PRIVACY_TOTAL = 0;
const PRIVACY_EMAIL = 1;
const PRIVACY_NAME = 2;
const PRIVACY_ADDRESS = 3;
const PRIVACY_PHONE = 4;
}
?>Example usage:
set($bf::PERM_READ);
$bf->set($bf::PERM_WRITE);
$bf->set($bf::PERM_ADMIN);
$bf->set($bf::PERM_ADMIN2);
$bf->set($bf::PERM_ADMIN3);
//turn permission PERM_ADMIN2 to off/false
$bf->clear($bf::PERM_ADMIN2); // sets $bf::PERM_ADMIN2 bit to false
// check if permission PERM_READ is on/true
if ($bf->get($bf::PERM_READ)) {
// can read
echo 'can read is ON';
}
if ($bf->get($bf::PERM_WRITE)) {
// can write
echo 'can write is ON';
}
if ($bf->get($bf::PERM_ADMIN)) {
// is admin
echo 'admin is ON';
}
if ($bf->get($bf::PERM_ADMIN2)) {
// is admin 2
echo 'admin 2 is ON';
}
if ($bf->get($bf::PERM_ADMIN3)) {
// is admin 3
echo 'admin 3 is ON';
}
?>Solution
You are kind of missing the point of using bitmasks.
You should be making use of simple bit operations.
If each bit represents a privacy settings, then the operations should be:
-
Check if a value is set, using & operator.
-
Set a value using the | operator (or |=).
-
Clear a value using the & operator (or &=).
And then your values should be powers of 2. Usually 0 is saved for a null value or invalid value.
Now the first 4 values correspond to 1 bit. And you can make use of PRIVACY_ALL by using the combination of all the other values.
i.e. In bits
This way if you set all the values individually, and then check PRIVACY_ALL, that will evaluate to true.
Here's some revised code, with examples at the end.
As an example, look at the values for the Error Constants in PHP. http://php.net/manual/en/errorfunc.constants.php
You should be making use of simple bit operations.
If each bit represents a privacy settings, then the operations should be:
-
Check if a value is set, using & operator.
($this->value & $n) == $n;-
Set a value using the | operator (or |=).
$this->value |= $n;-
Clear a value using the & operator (or &=).
$this->value &= ~$n;And then your values should be powers of 2. Usually 0 is saved for a null value or invalid value.
class UserPrivacySettings_BitField extends BitField
{
const PRIVACY_EMAIL = 1;
const PRIVACY_NAME = 2;
const PRIVACY_ADDRESS = 4;
const PRIVACY_PHONE = 8;
const PRIVACY_ALL = 15;
}Now the first 4 values correspond to 1 bit. And you can make use of PRIVACY_ALL by using the combination of all the other values.
i.e. In bits
PRIVACY_EMAIL = 0001
PRIVACY_NAME = 0010
PRIVACY_ADDRESS = 0100
PRIVACY_PHONE = 1000
PRIVACY_ALL = 1111This way if you set all the values individually, and then check PRIVACY_ALL, that will evaluate to true.
Here's some revised code, with examples at the end.
value = $value;
}
public function getValue() {
return $this->value;
}
public function get($n) {
return ($this->value & $n) == $n;
}
public function set($n) {
$this->value |= $n;
}
public function clear($n) {
$this->value &= ~$n;
}
}
class UserPrivacySettings_BitField extends BitField
{
const PRIVACY_EMAIL = 1;
const PRIVACY_NAME = 2;
const PRIVACY_ADDRESS = 4;
const PRIVACY_PHONE = 8;
const PRIVACY_ALL = 15;
}
$bf = new UserPrivacySettings_BitField();
echo "Setting PRIVACY_EMAIL";
$bf->set(UserPrivacySettings_BitField::PRIVACY_EMAIL);
var_dump($bf->get(UserPrivacySettings_BitField::PRIVACY_EMAIL));
var_dump($bf->get(UserPrivacySettings_BitField::PRIVACY_NAME));
var_dump($bf->get(UserPrivacySettings_BitField::PRIVACY_ADDRESS));
var_dump($bf->get(UserPrivacySettings_BitField::PRIVACY_PHONE));
var_dump($bf->get(UserPrivacySettings_BitField::PRIVACY_ALL));
echo "Setting PRIVACY_NAME";
$bf->set(UserPrivacySettings_BitField::PRIVACY_NAME);
echo "Setting PRIVACY_ADDRESS";
$bf->set(UserPrivacySettings_BitField::PRIVACY_ADDRESS);
echo "Setting PRIVACY_PHONE";
$bf->set(UserPrivacySettings_BitField::PRIVACY_PHONE);
var_dump($bf->get(UserPrivacySettings_BitField::PRIVACY_EMAIL));
var_dump($bf->get(UserPrivacySettings_BitField::PRIVACY_NAME));
var_dump($bf->get(UserPrivacySettings_BitField::PRIVACY_ADDRESS));
var_dump($bf->get(UserPrivacySettings_BitField::PRIVACY_PHONE));
var_dump($bf->get(UserPrivacySettings_BitField::PRIVACY_ALL));As an example, look at the values for the Error Constants in PHP. http://php.net/manual/en/errorfunc.constants.php
Code Snippets
class UserPrivacySettings_BitField extends BitField
{
const PRIVACY_EMAIL = 1;
const PRIVACY_NAME = 2;
const PRIVACY_ADDRESS = 4;
const PRIVACY_PHONE = 8;
const PRIVACY_ALL = 15;
}PRIVACY_EMAIL = 0001
PRIVACY_NAME = 0010
PRIVACY_ADDRESS = 0100
PRIVACY_PHONE = 1000
PRIVACY_ALL = 1111<?php
abstract class BitField {
private $value;
public function __construct($value=0) {
$this->value = $value;
}
public function getValue() {
return $this->value;
}
public function get($n) {
return ($this->value & $n) == $n;
}
public function set($n) {
$this->value |= $n;
}
public function clear($n) {
$this->value &= ~$n;
}
}
class UserPrivacySettings_BitField extends BitField
{
const PRIVACY_EMAIL = 1;
const PRIVACY_NAME = 2;
const PRIVACY_ADDRESS = 4;
const PRIVACY_PHONE = 8;
const PRIVACY_ALL = 15;
}
$bf = new UserPrivacySettings_BitField();
echo "Setting PRIVACY_EMAIL<br/>";
$bf->set(UserPrivacySettings_BitField::PRIVACY_EMAIL);
var_dump($bf->get(UserPrivacySettings_BitField::PRIVACY_EMAIL));
var_dump($bf->get(UserPrivacySettings_BitField::PRIVACY_NAME));
var_dump($bf->get(UserPrivacySettings_BitField::PRIVACY_ADDRESS));
var_dump($bf->get(UserPrivacySettings_BitField::PRIVACY_PHONE));
var_dump($bf->get(UserPrivacySettings_BitField::PRIVACY_ALL));
echo "Setting PRIVACY_NAME<br/>";
$bf->set(UserPrivacySettings_BitField::PRIVACY_NAME);
echo "Setting PRIVACY_ADDRESS<br/>";
$bf->set(UserPrivacySettings_BitField::PRIVACY_ADDRESS);
echo "Setting PRIVACY_PHONE<br/>";
$bf->set(UserPrivacySettings_BitField::PRIVACY_PHONE);
var_dump($bf->get(UserPrivacySettings_BitField::PRIVACY_EMAIL));
var_dump($bf->get(UserPrivacySettings_BitField::PRIVACY_NAME));
var_dump($bf->get(UserPrivacySettings_BitField::PRIVACY_ADDRESS));
var_dump($bf->get(UserPrivacySettings_BitField::PRIVACY_PHONE));
var_dump($bf->get(UserPrivacySettings_BitField::PRIVACY_ALL));Context
StackExchange Code Review Q#1509, answer score: 6
Revisions (0)
No revisions yet.