The bitwise operators and binary math in general have always been a mystery to me. If not for studying for the zend certification I still would probably not care to learn them :) However here I am and I finally got down the mystery of bits and bytes.
Feel free to check out my web blog at:
http://www.litfuel.net/plush
What this tutorial will cover:
1.
What are bits and bytes and binary math
2.
PHP's Bitwise Operators
3. A simple usecase for why you would want to use bitwise operators
PART 1 Bits, Bytes, and Binary Math
BINARY MATH INTRODUCTION |
The bitwise operators utilize something called Binary Math. If you already know binary math, skip ahead. Binary math is a BASE 2 numbering system, where as our normal everyday numbering system is a BASE 10 system. Think back to elementary school where we learned numbers this way...
Think of the number 4768. Thats a normal everyday decimal number.
If you write that out full its 4 THOUSAND, 7 HUNDRED, 6 TENS, 8 ONES
or (4 * 103) + (7 * 102) + (6 * 101) + (8 * 100) = 4768
The BASE 2 system has the same concept however it goes by 2's instead of 10s. So you can only have a value of 0 or 1. Lets look at a binary number
00101101 = (0 * 27) + (0 * 26) + (1 * 25) + (0 * 24) + (1 * 23) + (1 * 22) + (0 * 21) + (1 * 20) = 32 + 8 + 4 + 1 = 45
Wow thats alot of math. Lets break it down piece by piece starting with the first parentheses.
(0 * 27) which means 0 TIMES 2 to the POWER of 7 or 0 * ( 2 * 2 * 2 * 2 * 2 * 2 * 2) which basically comes out to 0 * 128 which equals 0 (0 times anything is 0)
so going down our binary number we can see it calculates like this:
0 - (0 * 128) = 0
0 - (0 * 64) = 0
1 - (1 * 32) = 32
0 - (0 * 16) = 0
1 - (1 * 8) = 8
1 - (1 * 4) = 4
0 - (0 * 2) = 0
1 - (1 * 1) = 1
so add those all up together 32 + 8 + 4 + 1 and you get 45
|
What is a bit? A bit is a representation of 1 or 0. Basically OFF and ON. Why do computers use such simple math? Well computers process with electric current so if the current is over a certain level the computer considers that to mean ON or 1 and if it is under that level it is set to OFF or 0.
What is a byte? A byte is made up of 8 bits and the highest value of a byte is 255, which would mean every bit is set. We will look at why a byte's maximum value is 255 in just a second.
What does a byte look like?
1 Byte ( 8 bits )
|
Place Value |
128
|
64
|
32
|
16
|
8
|
4
|
2
|
1
|
|
|
That is a representation of 1 Byte.
The "Place Value" column represents the math we did doing 2 to the power of 7,6,5,4,3,2,1,0
So if all bits are set and the value = 255 my byte would look like this
1 Byte ( 8 bits )
|
Place Value |
128
|
64
|
32
|
16
|
8
|
4
|
2
|
1
|
|
|
|
1
|
1
|
1
|
1
|
1
|
1
|
1
|
1
|
=
|
255 |
How do we get 255?
Lets take it right to left and add up all those values together
1 + 2 + 4 + 8 + 16 + 32 + 64 + 128 = 255
What would the number 22 look like?
1 Byte ( 8 bits )
|
Place Value |
128
|
64
|
32
|
16
|
8
|
4
|
2
|
1
|
|
|
|
0
|
0
|
0
|
1
|
0
|
1
|
1
|
0
|
=
|
22
|
2 + 4 + 16 = 22
Lets look at some other examples of decimal to binary, the ones on the end try for yourself.
43 = 00101011
4 = 00000100
230 = ?
65 = ?
31 = ?
PART II PHP'S BITWISE OPERATORS
You can find complete detail on the PHP bitwise operators here:
http://www.php.net/manual/en/language.operators.bitwise.php
What are going to cover?
We're going to cover the bitwise operators below and see how they work
Example |
Name |
Result |
$a & $b |
And |
Bits that are set in both $a and $b are set. |
$a | $b |
Or |
Bits that are set in either $a or $b are set. |
$a ^ $b |
Xor |
Bits that are set in $a or $b but not both are set. |
~ $a |
Not |
Bits that are set in $a are not set, and vice versa. |
$a << $b |
Shift left |
Shift the bits of $a $b steps to the left (each step means "multiply by two") |
$a >> $b |
Shift right |
Shift the bits of $a $b steps to the right (each step means "divide by two") |
Lets use two variables to get started with the "And" operator &.
The & or "And" operator takes two values and returns a decimal version of the binary values the left and right variable share. So using our tables above we can see that the only bit these two share is in the 8 position so $a & $b = 8.
$a
= |
9; |
$b
= |
10; |
echo
$a & $b; |
|
This would output the number 8. Why?? Well lets see using our table example
1 Byte ( 8 bits )
|
Place Value |
128
|
64
|
32
|
16
|
8
|
4
|
2
|
1
|
|
|
$a |
0
|
0
|
0
|
0
|
1
|
0
|
0
|
1
|
=
|
9
|
$b |
0
|
0
|
0
|
0
|
1
|
0
|
1
|
0
|
=
|
10
|
So you can see from the table the only bit they share together is the 8 bit. So 8 gets returned.. not too hard eh? Lets look at another example of the & operator.
$a
= |
36; |
$b
= |
103; |
echo
$a & $b; |
|
This would output the number 36. Why?? Well lets see using our table example again
1 Byte ( 8 bits )
|
Place Value |
128
|
64
|
32
|
16
|
8
|
4
|
2
|
1
|
|
|
$a |
0
|
0
|
1
|
0
|
0
|
1
|
0
|
0
|
=
|
36
|
$b |
0
|
1
|
1
|
0
|
0
|
1
|
1
|
1
|
=
|
103
|
So you can see the only bits these two share together are the bits 32 and 4 which when added together return 36. This operator is saying "I want to know what bits you both have set in the same column"
Lets move on to the | also known as the "OR" operator.
$a
= |
9; |
$b
= |
10; |
echo
$a | $b; |
|
This would output the number 11. Why?? Well lets see using our table example
1 Byte ( 8 bits )
|
Place Value |
128
|
64
|
32
|
16
|
8
|
4
|
2
|
1
|
|
|
$a |
0
|
0
|
0
|
0
|
1
|
0
|
0
|
1
|
=
|
9
|
$b |
0
|
0
|
0
|
0
|
1
|
0
|
1
|
0
|
=
|
10
|
If you notice we have 3 bits set, in the 8, 2, and 1 column.. add those up 8+2+1 and you get 11. It is just saying "I want to know what bits either one of you guys have set".
Moving on to the ^ operator also known as the "Xor" operator.
$a
= |
9; |
$b
= |
10; |
echo
$a ^ $b; |
|
This would output the number 3. Why?? Well lets see using our table example
1 Byte ( 8 bits )
|
Place Value |
128
|
64
|
32
|
16
|
8
|
4
|
2
|
1
|
|
|
$a |
0
|
0
|
0
|
0
|
1
|
0
|
0
|
1
|
=
|
9
|
$b |
0
|
0
|
0
|
0
|
1
|
0
|
1
|
0
|
=
|
10
|
The XOR operator wants to know "Tell me what bits you both have set but I dont want any bits you share" Notice we have 3 bits set but both $a and $b share the 8 bit, we dont want that one, we just want the 2 bit and the 1 bit that they each have set but don't share. Soooo 2+1 = 3
OK, here is one that gets tricky the ~ operator also known as the "NOT" operator.
$a
= |
9; |
$b
= |
10; |
echo
$a & ~$b; |
|
This would output the number 1. Why?? Well lets see using our table example
1 Byte ( 8 bits )
|
Place Value |
128
|
64
|
32
|
16
|
8
|
4
|
2
|
1
|
|
|
$a |
0
|
0
|
0
|
0
|
1
|
0
|
0
|
1
|
=
|
9
|
$b |
0
|
0
|
0
|
0
|
1
|
0
|
1
|
0
|
=
|
10
|
The NOT operator wants to know what is set in $a but NOT set in $b because we marked $b with the ~operator in front of it. So looking at our table we can see the only bit set in $a thats not in $b is 1.
What happens if we do this...
$a
= |
9; |
$b
= |
10; |
echo
~$a & $b; |
|
We get the value 2, because we want the bits set in $b but NOT set in $a this time, so since they both share the 8 bit, 2 bit is the only one $b has that $a does not.
BIT SHIFTING TIME!!!
This would output the number 64. Why?? Well lets see using our table example
1 Byte ( 8 bits )
|
Place Value |
128
|
64
|
32
|
16
|
8
|
4
|
2
|
1
|
|
|
$a - BEFORE! |
0
|
0
|
0
|
1
|
0
|
0
|
0
|
0
|
=
|
16
|
$a - AFTER! |
0
|
1
|
0
|
0
|
0
|
0
|
0
|
0
|
=
|
64
|
How do we get 64? well bit shifting tells PHP to take the variable $a which in our case is 16 and shift if 2 bits which is basically like saying take 16 and multiply it by 2 twice. So 16 X 2 = 32 x 2 = 64
So what useful things can you do with the bitwise operations?
Here is a VERY simple and watered down user persmissions system. This is great if you have many classes of persmission for users for example...
a user can...
read articles
write articles
edit articles
be an local Administrator
be a global Administrator
So you can setup your permission rules like this in your configuration file
<?php $read = 1; $write = 2; $readwrite = 16; $local_admin = 32; $global_admin = 64; $jim = 96; $mike = 16; echo "Is Mike Allowed to edit? he has an access level of 16<BR>"; if($mike & 32) { echo 'YES MIKE CAN EDIT'; } else { } echo "<BR><BR>Is Jim Allowed to edit? he has an access level of 96<BR>"; if($jim & 32) { } else { } ?>
|
|
When you run that code you'll see
Is Mike Allowed to edit? he has an access level of 16
NO HE CANNOT
Is Jim Allowed to edit? he has an access level of 32
YES JIM CAN EDIT
Using the AND operator we can clearly see if Mike has the 32 bit set that is required for this local admin operation, not only is Jim a local admin but he's also a global admin with the 64 and 32 bit set giving him a 96 permission level. Imagine if you had 20 different levels of access in your application, being able to store all those in a single integer is VERY handy instead of having to do something like
if(is_local_admin && is_global_admin && can_edit_articles && can_view_articles) etc.... that could get long, ugly and hard to manage.
Thats about all I have time for at the moment, but I hope to add more useful things you can do with bitwise operators in the future.
If you have any questions feel free to email me at
jplush76@gmail.com
| | Berufsbegleitend MAS HCI Design Hochschulen Rapperswil & Basel |
| | |
here is a binary cartoon to help you out :) Bitwise ownzors
|