Location: PHPKode > scripts > Bit Options > bit-options/BitOptions.php
<?php
/*
 * @author Pulni4kiya <hide@address.com>
 * @date 2008-09-18
 * @version 3.0 2008-09-21
 */

//Used for the default value of $use_strings (when true, uses strings).
define('BIT_OPTIONS_USE_STRINGS', false);
//Used to check if an exception should be thrown when a parameter which should be boolean is not.
define('BIT_OPTIONS_BOOL_EXCEPTION', true);

class BitOptions implements ArrayAccess, IteratorAggregate {
	private $options;
	private $use_strings;
	
	public function offsetExists($offset) {
		$this->checkOffset($offset);
		if ($this->use_strings) {
			return ($offset <= $this->options*8);
		}
		else {
			return ($offset <= 32);
		}
	}
	public function offsetGet($offset) {
		return $this->CheckOption($offset);
	}
	public function offsetSet($offset, $value) {
		$this->TurnOption($offset, $value);
	}

	public function offsetUnset($offset) {
		$this->TurnOption($offset, false);
	}

    public function getIterator() {
        return new ArrayIterator($this->GetOptions($this));
    }
	
	public function __construct($use_strings = BIT_OPTIONS_USE_STRINGS, $options = null) {
		$use_strings = $this->getBool($use_strings);
		$this->use_strings = $use_strings;
		if ($options != null) {
			if (!$use_strings && !is_numeric($options)) throw new Exception('Creating BitOptions object with wrong parameters');
			$this->options = $options;
		}
		else {
			if ($use_strings == true) $this->options = pack("C", 0);
			else $this->options = 0;
		}
	}
	
	public function CheckOption($option) {
		$this->checkOffset($option);
		$user_options =& $this->options;
		$use_strings = $this->use_strings;
		if ($use_strings) {
			$start = ceil($option/8);
			$options_fragment = substr($user_options, -$start, 1);
			if (empty($options_fragment)) return false;
			$option -= ($start-1)*8;
		}
		else {
			$options_fragment = $user_options;
		}
		$option_to_check = self::CalculateOptions($option, $use_strings);
		return (($option_to_check->options & $options_fragment) == $option_to_check->options);
	}
	
	public function TurnOption($option, $switch) {
		$this->checkOffset($option);
		$switch = $this->getBool($switch);
		$user_options =& $this->options;
		$use_strings = $this->use_strings;
		$option_to_change = self::CalculateOptions($option, $use_strings);
		$option_to_change = $option_to_change->options;
		if ($use_strings) {
			if (strlen($user_options) > ceil($option/8)) $option_to_change = str_repeat(pack("C",0),strlen($user_options)-ceil($option/8)) . $option_to_change;
			else $user_options = str_repeat(pack("C",0),ceil($option/8)-strlen($user_options)) . $user_options;
		}
		if ($switch) {
			$user_options |= $option_to_change;
		}
		else {
			$user_options &= ~$option_to_change;
		}
	}
	
	public static function CalculateOptions($options, $use_strings = BIT_OPTIONS_USE_STRINGS) {
		$use_strings = self::getBool($use_strings);
		if (!is_array($options)) {
			self::checkOffset($options);
			if ($use_strings) {
				$options--;
				$nulls = floor($options/8);
				$options = $options%8;
				$opts = pack("C", 1 << $options) . str_repeat(pack("C", 0), $nulls);
				$result = new BitOptions($use_strings, $opts);
			}
			else {
				if ($options > 32) throw new Exception("Using option > 32 with int");
				$opts = 1 << ($options - 1);
				$result = new BitOptions($use_strings, $opts);
			}
		}
		else {
			$result = new BitOptions($use_strings);
			foreach ($options AS $value) $result->TurnOption($value, true);
		}
		return $result;
	}
	
	public static function GetOptions($options, $use_strings = BIT_OPTIONS_USE_STRINGS) {
		$use_strings = self::getBool($use_strings);
		if (!($options instanceof BitOptions)) $options = new BitOptions($use_strings, $options);
		else $use_strings = $options->use_strings;
		$array = array();
		$max_option = ($use_strings) ? strlen($options->options)*8 : 32;
		for($i=1; $i<=$max_option; $i++) {
			if ((!$use_strings) && 1<<($i-1)>$options->options) break;
			if ($options->CheckOption($i)) $array[] = $i;
		}
		return $array;
	}
	
	public function __get($name) {
		if (empty($this->$name) == false) return $this->$name;
		else return null;
	}
	
	public function __toString() {
		if ($this->use_strings == true) return $this->options;
		else return (string) $this->options;
	}
	
	private static function checkOffset($offset) {
		if (!is_numeric($offset)) throw new Exception('The option value must be numeric');
		if ($offset<1) throw new Exception('The option value must be a number > 0');
	}
	
	private static function getBool($bool) {
		if (BIT_OPTIONS_BOOL_EXCEPTION && !is_bool($bool)) throw new Exception('Expected boolean parameter is not a boolean');
		return ($bool == true);
	}
}
?>
Return current item: Bit Options