<?php
class Flags {
private $_flagNames = array();
private $_flagInts = array();
private $listCount = 0;
public function __construct() {
$flags = func_get_args();
$flagList = array();
if(count($flags) > 0) {
if(is_array($flags[0])) $flags = $flags[0];
$count = count($flags);
$piece = 31;
if($count > $piece) {
$i=0;
$listCount = 0;
while($i<$count) {
$flagList[] = array_slice($flags,$i,$piece);
$i += $piece;
$listCount++;
}
} else {
$flagList[0] = $flags;
$listCount = 1;
}
foreach($flagList as $i=>$subList) {
$count = 0x01;
$this->_flagInts[$i] = 0x00;
foreach($subList as $j=>$flag) {
$this->_flagNames[$i][$flag] = $count;
$count = $count * 2;
}
}
$this->listCount = $listCount;
}
}
private function _invalidFlag($flag,$flagIDX) {
return ($flagIDX === false || !array_key_exists($flagIDX,$this->_flagNames) || !array_key_exists($flag,$this->_flagNames[$flagIDX]));
}
private function _findFlag($flag) {
foreach($this->_flagNames as $i=>$flagList) {
if(array_key_exists($flag,$flagList)) return $i;
}
throw new Exception('Flag '.$flag.' does not exist.');
}
private function _isFlagSet($flag,$flagIDX) {
if($this->_invalidFlag($flag,$flagIDX)) return false;
$isset = $this->_flagInts[$flagIDX] & $this->_flagNames[$flagIDX][$flag];
return ($isset == $this->_flagNames[$flagIDX][$flag] ? true : false);
}
private function _setFlag($flag,$on,$flagIDX) {
$flag = strtolower($flag);
$isset = $this->_isFlagSet($flag,$flagIDX);
if($this->_invalidFlag($flag,$flagIDX)) return false;
if($on == true && !$isset) {
$this->_flagInts[$flagIDX] = $this->_flagInts[$flagIDX] | $this->_flagNames[$flagIDX][$flag];
} else if($on == false && $isset) {
$this->_flagInts[$flagIDX] = $this->_flagInts[$flagIDX] ^ $this->_flagNames[$flagIDX][$flag];
}
}
private function _forceBool($val) {
if(is_bool($val)) {
return $val;
} else if(is_string($val)) {
if(
strtolower($val) == 'on'
||
strtolower($val) == 'true'
) return true;
else return false;
} else if(is_numeric($val)) {
return (bool) $val;
} else {
throw new Exception('Set value not of expected type. Expected string|numeric|boolean. Recieved '.gettype($val));
}
}
public function toggleFlag($flag) {
$idx = strtolower($flag);
$flagIDX = $this->_findFlag($flag);
$set = !$this->_isFlagSet($flag,$flagIDX);
$this->_setFlag($flag,$set,$flagIDX);
return $set;
}
public function setFlag($flag,$on = true) {
$flag = strtolower($flag);
$on = $this->_forceBool($on);
$flagIDX = $this->_findFlag($flag);
$this->_setFlag($flag,$on,$flagIDX);
return $on;
}
public function isFlagSet($flag) {
$flag = strtolower($flag);
$flagIDX = $this->_findFlag($flag);
return $this->_isFlagSet($flag,$flagIDX);
}
public function __get($idx) {
return $this->isFlagSet($idx);
}
public function __set($name, $value) {
if(!is_bool($value) && !is_numeric($value)) {
// invalid values...
throw new Exception('Setting flag expected boolean value.');
}
$this->setFlag($name,(bool)$value);
}
public function __call($name,$args) {
$this->toggleFlag($name);
}
// niceties
public function __toString() {
$str = '';
$format = '%1$40b';
for($i=count($this->_flagInts)-1,$l=0;$i>=$l;$i--) {
$bits = trim(sprintf($format,$this->_flagInts[$i]));
while(strlen($bits) < 31) {
$bits = '0'.$bits;
}
$str .= $bits;
}
return $str;
}
public function getData() {
return serialize($this->_flagInts);
}
public function setData($data) {
$this->_flagInts = unserialize($data);
while(count($this->_flagInts) < $this->listCount) {
$this->_flagInts[] = 0x00;
}
while(count($this->_flagInts) > $this->listCount) {
array_splice($this->_flagInts,count($this->_flagInts)-1,1);
}
}
}
?>