Title: How to get list of decimal numbers "hidden" in binary number in PHP?
Tags: php;numbers;integer
Question: firstly, I very much apologize for my poorly written title of this question. So please someone with native English, change the title appropriately. My question is rather simple, it follows:
I am using integer to store multiple types of one item. For example:
TYPE A = 1
TYPE B = 2
TYPE C = 4
TYPE D = 8
TYPE E = 16
etc...
Now the item in DB has type value 14, that means that it has been assigned to TYPE B+C+D. If it would have type value for example 9, it would mean it has been assigned to TYPE A+D.
I need a function which I would supply with single type integer and this function would return array of integer types.
I could iterate through all the integers and compare them with the number, but that's what I am using now, but I am looking for some more effective way, if it exists ?
Thanks in advance for your help.
Comment: It sounds like you're trying to use a [bitmask](http://en.wikipedia.org/wiki/Mask_(computing)); typically you "retrieve" values via binary AND operations.

Here is the accepted answer: Here's a function without any loops (mostly done for the fun of it :) ):
function getTypes($int)
$types = array('Type A','Type B','Type C','Type D','Type E');//defining types
$t = array_reverse(str_split(decbin($int)));//converting $int to an array of bits
$types = array_slice($types,0,ceil(log($int,2)));//slicing the array to the same size as number of bits in the $int
$t = array_combine($types,$t);// Creating a new array where types are keys and bits are values
return array_keys($t,1);// returning an array of keys which have a value of 1
However it doesn't mean that it is efficient. If you use a bitmask you better of checking values using bitwise operators like bitwise and (&amp;).
For example if you want to check if your integer contains Type D and Type E you should do
if ($integer &amp; 8 &amp; 16)
To check for each individual type I would us a loop with bitshift operator
function getTypes($int)
$result = array();
$types = array('Type A','Type B','Type C','Type D','Type E');
foreach($types as $type)
if ($int &amp; 1)//checking if last bit is 1 (exactly the same as if($int%2) )
$result[]=$type;
$int&gt;&gt;=1;//shifting integer's bits to the right (exactly the same as $int = $int / 2)
return $result;
Comment for this answer: My bad, I forgot to slice types array to the correct size. Should work fine now.
Comment for this answer: Maybe I'm not getting something, but it doesn't jbrown@example.com. Throws 2 warnings and returns null.

Here is another answer: How's this? http://codepad.org/AzgdPsL1
To explain what's going on:
I create a $types array of all the valid types that exist between the range of 1 to $max_bit bits.
Looping while the number is greater than 0, it gets bitwise ANDed with 1. If it turns out that evaluates to true, this means that the LSB is set, so the type at the head of the $type array applies to this number. The current type is added to the return array.
The number is then shifted to the right by one bit.
<?php
function num2type( $num)
$max_bit = 5;
$types = array_combine( range( 1, $max_bit), range( ord( 'A'), ord( 'A') + $max_bit - 1));
$return = array();
while( $num &gt; 0)
$current_type = array_shift( $types);
if( $num &amp; 0x1)
{
$return[] = chr( $current_type);
}
$num = $num &gt;&gt; 1;
return $return;
var_dump( num2type( 8)); // array(1) { [0]=&gt; string(1) "D" }
var_dump( num2type( 31));
var_dump( num2type( 14));
Output (for 31):
array(5) {
[0]=&gt;
string(1) "A"
[1]=&gt;
string(1) "B"
[2]=&gt;
string(1) "C"
[3]=&gt;
string(1) "D"
[4]=&gt;
string(1) "E"
Output for 14:
array(3) {
[0]=&gt;
string(1) "B"
[1]=&gt;
string(1) "C"
[2]=&gt;
string(1) "D"

Here is another answer: $a = 10;
$scan = 1;
$result = array();
while ($a &gt;= $scan){
if ($a &amp; $scan)
$result[] = $scan;
$scan<<=1; //just a bit shift
var_dump($result);
Comment for this answer: `$scan <<= 1` would surely be better than `$scan*=2`, no?

Here is another answer: function check_flag($field, $bit)
return (($field | $bit) === $field) ? TRUE : FALSE;
$types = array('A' =&gt; 1, 'B' =&gt; 2, 'C' =&gt; 4, 'D' =&gt; 8, 'E' =&gt; 16);
$db_value = 14;
var_dump(check_flag($db_value, $types['B']));
... just make sure that you cast the value fetched from the database to integer.
Edit: Now that I read you need all of the types that are set, here's some more logic:
$set = array();
foreach ($types as $key =&gt; $value)
if (check_flag($db_value, $value)) $set[] = $key;

{'source': 'StackExchangeDataset', 'subset': 'stackoverflow.com', 'metadata': {'AnswerCount': 4, 'CommentCount': 1, 'ContentLicense': 'CC BY-SA 3.0', 'CreationDate': '2011:00:11/08/11', 'FavoriteCount': None, 'PostTypeId': 1, 'Tags': '<php><numbers><integer>', 'Title': 'How to get list of decimal numbers "hidden" in binary number in PHP?', 'ViewCount': 202, 'id': 8050937, 'user_AboutMe': '<p>My favourite programming languages: PHP5, Javascript, jQuery</p>\n\n<h1>SOreadytohelp</h1>\n', 'user_AccountId': 163253.0, 'user_DisplayName': 'Frodik', 'user_Reputation': 14364.0, 'user_Views': 668.0, 'user_id': 385264.0}}