We'll start from the beginning.
Computers are run by electrical current; the current is either there or it isn't. At the most fundamental levels, computers are only checking for the presence or lack of electrical current.
This leads to the binary digit, or bit. It is called a binary digit because it can only contain two possible values, 0 or 1. We call it a bit for short because we're lazy.
Now, humans like to group things, it makes our lives easier. So we arbitrarily decided that 8 bits is called a byte, and 4 bytes is a word. (On some platforms a word could be more than 4 bytes, but that's irrelevant).
PHP is different than most programming languages in that it isn't strongly typed, meaning that PHP converts relatively freely from an integer to a string to a floating point number. Other languages, like C, are very strongly typed. An integer can only interact with other data types that are a type of a number.
Let's say that you're programming in C and that you happen to know that an integer in C is 1 word, which is the same as 4 bytes, which is the same as 32 bits.
This means that you can think of any integer in C has being a string of length 32 where every place in the string is a 0 or a 1.
For example:
0000 0000 0000 0000 0000 0000 0000 0000
0110 0010 0101 1111 0101 1000 0000 0001
Let's throw a little bit of math in here for fun. Ignoring negative numbers, how many different numbers can we represent with such a string?
Starting small...
Bit string of length 1
0
1
We can store two values in a string of length 1, notice that this is the same as 2^1
Bit string of length 2
00
01
10
11
We can store four values in a string of length 2, notice that this is the same as 2^2
If we keep going, we find that we can store 2^n possible values in a bit string of length n. A bit string of length 32 can store 2^32 possible integers, which is why you can store some really large numbers in an integer variable! (Note to the more advanced reader: Yes, I'm ignoring sign bits. Don't get hung up on the details.)
Explained in other words, every unique combination of a bit string is mapped to a unique integer. It's done through a mathematical formula which isn't really important for this discussion. But, rest assured that the following is true:
0000 equals 0
0001 equals 1
0010 equals 2
0011 equals 3
...
1110 equals 14
1111 equals 15
Now, I ask you a question. You're designing a website that has 16 permissions that are on or off. The user has permission to do this or the user doesn't.
Here is one approach. You can create 16 integer variables. Set a variable to 0 to indicate the user doesn't have permission. Set a variable to 1 to indicate that they do. But what have you done, you've created 16 integers, each requiring 4 bytes of memory space. That's 64 total bytes of storage.
Wouldn't it be really cool if we could store all those settings in just 4 bytes? The answer is yes and here's how you do it. You let each bit of a single integer variable represent a permission. We count bit positions starting from 0 and from the right of the bit string.
0101 - bit string
3210 - bit position
In position 0 (bottom) we have a value of 1 (top). In position 1 we have a value of 0. In position 2 we have a value of 1. In position 3 we have a value 0.
If each position (0, 1, 2, & 3) represent a different permission, we can store 4 permissions in just 4 bits! This means that a 32 bit integer can be used to store 32 permissions that have an on or off setting.
So how do we get at the individual bits? We use a mask. This would be a good point to look up a tutorial on hexadecimal, but for reference:
0000 = 0 = 0
0001 = 1 = 1
0010 = 2 = 2
0011 = 3 = 3
0100 = 4 = 4
0101 = 5 = 5
0110 = 6 = 6
0111 = 7 = 7
1000 = 8 = 8
1001 = 9 = 9 We have now run out of 0-9 digits to represent values, so we use letters!
1010 = 10 = A
1011 = 11 = B
1100 = 12 = C
1101 = 13 = D
1110 = 14 = E
1111 = 15 = F
What we have here is a mapping of 4 bits to a single value in the range of 0 through 9, A through F. You start a hexadecimal number with 0x and then end it with the digits (0-9, A-F).
For example:
The bit string:
0110 0010 0101 1111 0101 1000 0000 0001
is equivalent to the hex number:
0x625F5801
Look at that and absorb it until it makes sense; it's nothing more than a shorter way to write a bit string!
You might be familiar with the logical operators in PHP that compare values. These are && and ||. Well guess what, there are binary operators that do very similar tasks.
& - From two values, make a bitwise comparison and return a composite result based on AND.
For example:
0111 & 1010 = 0010 - Notice that the result only contains a 1 where both bit strings also contained a 1.
| - From two values, make a bitwise comparison and return a composite result based on OR.
For example:
0101 | 1010 = 1111 - Notice that the result contains a 1 where either bit string contained a 1.
There is also a negation operator:
~ From a single value, flip all of the bits.
For example:
~0101 = 1010 - Notice how all the bits changed to the opposite value of what they were.
Now we can start packing multiple values into a single set of 32 bits (or an integer).
<?php
define('MOD_FORUMS', 0x00000001);
define('DEL_THREAD', 0x00000002);
...
define('BOOT_USER', 0x80000000);
var $perms = 0x00000000; // We init our current permissions to NONE
// Let's turn on DEL_THREAD
$perms = $perms | DEL_THREAD; // $perms now contains 0x00000002
// Let's turn on MOD_FORUMS
$perms = $perms | MOD_FORUMS; // $perms now contains 0x00000003 (the right most set of four bits is 0011, or 3 in hex)
// Let's turn on our last permission
$perms = $perms | BOOT_USER; // perms now contains 0x80000003
// Now lets check for a permission
if($perms & MOD_THREAD){
// Check if the MOD_THREAD bit is turned on!
echo 'user can mod a thread';
}
// Now let's turn a permission off
// here we use the negation operator, we flip all of the bits in the permission constant and
// AND it with the current set of permissions
// Do it on paper and see why this turns off only one permission out of all of them :D
$perms = $perms & ~MOD_THREAD;
?>
Wow! That's great for on or off type permissions.
But now you might be thinking what if a permission has more than one value? You can still pack those types of settings using bitwise operators. I'll leave that as an exercise for you to research or discover on your own though.
(EDIT) Because you turn permissions on with |, silly me.