PHP A to ZCE: Bitwise Operations
This article is part of the series “PHP A to Zend Certified Engineer”.
In PHP A to ZCE, I will take you through 26
different yet equally important topics that will help you become a Zend
Certified Engineer. Even if you're not interested in sitting the ZCE-PHP
exam, these topics will elevate your understanding of PHP to a whole
new level and allow you to become the guru in your company.
Read more about PHP A to Zend Certified Engineer...
Bitwise operations allow evaluation and manipulation of specific
bits within an integer. In this article I will show each of the bitwise
operations that are available and how to practically use them within
PHP.About Bitwise Operations
- Primarily used as a series of on/off "switches".
- Each switch corresponds to a single bit in an integer
- Bitwise operators allow you to turn on or turn off various switches
- Easiest to think of terms of binary numbers and operate with hex values
- Bits are read from right-to-left
13
into binary digits. Think of this number as a series of switches, the
first, third and fourth "switches" are enabled (reading from the right).
Listing 9 listing-9.txt
Position: 128 64 32 16 8 4 2 1 ---------------------------------- Number: 0 0 0 0 1 1 0 1
Available Operators
There are six bitwise operations available. All operations use two values (that is, they have a left and a right operand) except for "not", which is a unary operator (has a single operand only).The operations and their result are as follows:
- And (
$c = $a & $b;): Bits that are set in both$aand$bare set in$c. - Or (
$c = $a | $b): Bits that are set in either$aand$bare set in$c. - Exclusive Or (Xor) (
$c = $a ^ $b): Bits that are set in one and not the other are set in$c. - Not (
$c = ~$a): Bits that are set in$aare not set in$c. Bits that are not set in$aare set in$c. - Shift Left (
$c = $a << $b):$bindicates the number of positions the bits in$aare to move left. Each position move in effect is the same as multiplying by2. - Shift Right (
$c = $a >> $b):$bindicates the number of positions the bits in$aare to move right. Each position move in effect is the same as dividing by2(the remainder is ignore since we're operating on integers).
$a = $a & $b;can be shortened to$a &= $b;$a = $a | $b;can be shortened to$a |= $b;$a = $a ^ $b;can be shortened to$a ^= $b;
Hexadecimal Numbers
- Every four bits can be represented by a single hex digit
- Hex is 0-9, A=10, B=11, C=12, D=13, E=14, F=15
- The number
13can be represented byDin hex - All hex numbers are preceded by
0x, meaning13is actually0xD. - All switches on:
0xF- all switches off:0x0 - You can output hex numbers using the
%Xswitch in sprintf()
The And Operation
Bits that are set in both$a and $b are set in $c.
Listing 1 listing-1.php
$a = 0xD; // 13 in decimal, 1101 in binary $b = 0x7; // 7 in decimal 0111 in binary $c = $a & $b; /* 1101 (13, 0xD) & 0111 (7, 0x7) ---- 0101 (5, 0x5) */ echo $c; // outputs 5
The Or Operation
Bits that are set in either$a and $b are set in $c.
Listing 2 listing-2.php
$a = 0xD; // 13 in decimal, 1101 in binary $b = 0x7; // 7 in decimal 0111 in binary $c = $a | $b; /* 1101 (13, 0xD) | 0111 (7, 0x7) ---- 1111 (15, 0xF) */ echo $c; // outputs 15
The Xor (Exclusive Or) Operation
Bits that are set in one and not the other are set in$c.
Listing 3 listing-3.php
$a = 0xD; // 13 in decimal, 1101 in binary $b = 0x7; // 7 in decimal 0111 in binary $c = $a | $b; /* 1101 (13, 0xD) ^ 0111 (7, 0x7) ---- 1010 (10, 0xA) */ echo $c; // outputs 10
The Not Operation
Bits that are set in$a are not set in $c. Bits that are not set in $a are set in $c.
Listing 4 listing-4.php
$a = 0xD; // 13 in decimal, 1101 in binary $c = ~$a /* ~ 1101 (13, 0xD) ---- 0010 (2, 0x2) */ echo $c; // outputs 2
The Shift Left Operation
$b indicates the number of positions the bits in $a are to move left. Each position move in effect is the same as multiplying by 2.
Listing 5 listing-5.php
$a = 0xD; // 13 in decimal, 1101 in binary $b = 2; $c = $a << $b; /* 000001101 (13, 0xD) --------- << 2 --------- 000110100 (52, 0x34) */ echo $c; // outputs 52 echo $a * 2 * 2; // outputs 52
The Shift Right Operation
$b indicates the number of positions the bits in $a are to move right. Each position move in effect is the same as dividing by 2 (the remainder is ignore since we're operating on integers).
Listing 6 listing-6.php
$a = 0xD; // 13 in decimal, 1101 in binary $b = 1; $c = $a >> $b; /* 000001101 (13, 0xD) --------- >> 1 --------- 000000110 (6, 0x6) */ echo $c; // outputs 6 echo floor($a / 2); // outputs 6 // floor is used because the output must be an int
Practical Example 1: PHP Error Reporting
- PHP's error reporting system is an example of using bitwise operations and switches
- You can change the reporting level by turning switches on or off and passing the result to error_reporting()
Listing 10 listing-10.txt
E_ERROR = 1 = 0001 = 0x1 E_WARNING = 2 = 0010 = 0x2 E_PARSE = 4 = 0100 = 0x4 E_NOTICE = 8 = 1000 = 0x8
- To enable errors and warnings, use
E_ERROR | E_WARNING
Listing 11 listing-11.txt
E_ERROR = 0001
E_WARNING = 0010
----
0011
- You can check if a particular level is enabled using "and"
- If that switch is not enabled the result will be zero (
0x0)
Listing 7 listing-7.php
error_reporting(E_ERROR | E_WARNING); if (error_reporting() & E_WARNING) { // E_WARNING is enabled } /* error_reporting(): 0011 E_WARNING: 0010 ---- & 0010 - Therefore E_WARNING is enabled! */
Practical Example 2: IP Addresses and Subnet Masks
- You can use bitwise operations to see if an IP address is within a given subnet
- You need the subnet and the subnet mask to determine this
- You also need to convert the IP address to an integer representation so bitwise operations will work: ip2long() and long2ip() help with this.
Listing 8 listing-8.php
$ips = array( '192.168.0.25', '10.0.0.1' ); $subnet = ip2long('192.168.0.0'); $subnetMask = ip2long('255.255.255.0'); foreach ($ips as $ip) { $longIp = ip2long($ip); if (($longIp & $subnetMask) == $subnet) { echo sprintf("%s is in %s subnet\n", $ip, long2ip($subnet)); } else { echo sprintf("%s is not in %s subnet\n", $ip, long2ip($subnet)); } } /* Output: 192.168.0.25 is in 192.168.0.0 subnet 10.0.0.1 is not in 192.168.0.0 subnet */
Note: Be sure to use brackets appropriately. If you don't use brackets in the above if statement, the
== comparison is performed before the bitwise operation.Further Reading
Other Options
- Download a PDF version of this article
- Put your PHP knowledge to the test with our online and iPad/iPhone quizzes
- View or post comments for this article
- Browse similar articles by tag: PHP, ZCE
- Read related articles:
No comments:
Post a Comment