Oleg Charnyshevich
Oleg Charnyshevich

Oleg Charnyshevich

Understanding Bitwise Operators with PHP

Understanding Bitwise Operators with PHP

One of the unknown features in PHP is Bitwise Operators. In the article, we will learn things through practice with a real example!

Oleg Charnyshevich's photo
Oleg Charnyshevich
·Oct 13, 2021·

5 min read

Subscribe to my newsletter and never miss my upcoming articles

Bit operations are rare in the PHP world, however, in books, articles, or other sources, you might find something like:

$memory = memory_get_usage() >> 20;

You may get confused. What is ">>"? So, let's look at the documentation .

$a >> $b Shift the bits of $a $b steps to the right (each step means "divide by two")

WTF?! Why do you need it at all? So let's dive into it.

Many people know that binary (or base-2) a numeric system that only uses two digits — 0 and 1. Computers operate in binary, meaning they store data and perform calculations using only zeros and ones. So, for example, a computer will represent the number 6 as 00000110.

Bit Rotation : A rotation (or circular shift) is an arithmetic operation.

  • In the left rotation, the bits that fall off at the left end are put back at the right end.
  • In the right rotation, the bits that fall off at the right end are put back at the left end.

Let's back to our operator ">>".

$n = 6;       // 00000110
$k = $n >> 1; // 00000011

We can see that the bits that fall off at the right end are put back at the left end. So the current binary value 00000011 in decimal is 3. We just shifted one bit, and as a result, we divided the value by 2.

If we were to shift 2 bits, we would divide by 4.
If we were to shift 3 bits, we would divide by 8.

Wow, that's the power of two!

Get back to the example >> 20. It means that we are dividing the value by 2 to the power of 20. It is easy to remember that 2 ^ 10 = 1024. So

$memory = memory_get_usage() / (1024 * 1024);

Since memory_get_usage() returns a value in bits, we just converted it to megabytes. It turns into a very handy function:

$memory = memory_get_usage() >> 10; // convert it to kilobytes (KB)
$memory = memory_get_usage() >> 20; // convert it to megabytes (MB)
$memory = memory_get_usage() >> 30; // convert it to gigabytes (GB)
$memory = memory_get_usage() >> 40; // convert it to terabyte (TB)

If right rotation means division, then left rotation, on the contrary, means multiplication.

$y = 5;         // 000000101
echo $y << 2;   // 000010100 (5 * 4 = 20)

Are there other operators besides right/left rotation?

There are 4 more operations - AND & , OR | , XOR ^, NOT ~. Let's see it in action below.

What's the best way to use bitwise operations?

The most convenient to use bitwise operations, not in multiplication and division, but is using a bitwise mask, for example, to differentiate access rights or other similar things.

We can turn four values into a four-bit value, in which 1 means the user has the given right, and 0 does not.

define('U_READ',   1 << 0);                             // 0001
define('U_CREATE', 1 << 1);                             // 0010
define('U_EDIT',   1 << 2);                             // 0100
define('U_DELETE', 1 << 3);                             // 1000
define('U_ALL', U_READ | U_CREATE | U_EDIT | U_DELETE); // 1111

In the first four lines, we defined the constants by shifting bits to the left. After that, we used the OR | operator on the last line. The bitwise OR operator (|) returns a 1 in each bit position for which the corresponding bits of either or both operands are 1s. Example:

$x = 3;         // 0011
$y = 5;         // 0101
echo $x | $y;   // 0111 (7)

Therefore, we can set any permissions for the user:

Access Rights using Binary Masks.png

$userPermission =  U_READ;             // Only read
$userPermission =  U_READ | U_CREATE;  // Only read and create
$userPermission =  U_ALL ^ U_DELETE;   // All rights except deletion
$userPermission =  U_ALL & ~ U_DELETE; // Again all rights except deletion

In the example above, there are 3 new operators.

Example:

#XOR
$x = U_ALL;       // 1111
$y = U_DELETE;    // 1000
echo $x ^ $y;     // 0111
#AND
$x = U_ALL;       // 1111
$y = U_DELETE;    // 1000
echo $x & $y;     // 1000
#NOT
$y = U_DELETE | U_READ;    // 1001
echo ~$y;                  // 0110 (inverted)

What happens if we use AND + NOT operators?

In the example below, use the two operators together. The bitwise NOT operator (~) will be executed first, followed by the bitwise AND operator (&).

...
$userPermission =  U_ALL & ~ U_DELETE; // Again all rights except deletion

U_ALL        1111
~ U_DELETE   0111
RESULT       0111

Is there any difference between the XOR and AND + NOT operators?

The difference between these options is that in the first case, the bit switches. If it was 1, then it will become 0, and vice versa. The second option makes the bit equal to 0, regardless of its current value.

If we want to remove any access right, do the following:

$userPermission &= ~ U_DELETE;    // prohibit deletion

A few more examples:

To check the bits (in our case, the access rights), we can use the following conditions.

if ($userPermission & U_READ)               // is there a right to read?
if ($userPermission & (U_READ | U_DELETE))  // is there a right to read or/and delete?

One more example:

// A lot of code duplication
if ($error['type'] == E_ERROR 
 || $error['type'] == E_PARSE 
 || $error['type'] == E_COMPILE_ERROR) {}
//Better
if (in_array($error['type'], [E_ERROR, E_PARSE, E_COMPILE_ERROR])) {}
//Perfect)
if ($error['type'] & (E_ERROR | E_PARSE | E_COMPILE_ERROR)) {}

Although error codes in PHP are specially designed for bitwise operations, developers usually use comparison operators. But now you know a different approach 😉

Conclution

Thanks for reading this article! I hope you now understand bitwise operators and can utilize them in your PHP code (or in many other languages!). if you have any questions or comments, please leave them below. I appreciate any feedback!

Stay tuned for new articles by following me on Twitter or LinkedIn! Subscribe to my newsletter or RSS. Drop me an email if you have any questions.

 
Share this