If, like me, you've never thought about how PHP deals with binary, the output of the bitwise NOT may confuse you. For instance, this:
$bin = 2;
$notbin = ~$bin;
echo "Bin: " . decbin($bin) . " !bin: " . decbin($notbin) . "\n";
returns this:
Bin: 10 !bin: 1111111111111111111111111111111111111111111111111111111111111101
The reason is that all binary numbers are treated as 32 bits, even if you've manually entered less. In order to get the result I expected (01), it was necessary to AND the result with the number of bits I wanted: in this case, 2 (the number 3, in decimal). Be aware that all return values will have zeros removed from the left until they reach a bit that is set to 1. Continuing the above example, the following:
$notbin_2 = ~$bin & '3';
echo "!bin & 3: " . decbin($notbin_2) . "\n";
returns this:
!bin & 3: 1
Note that the actual value was a string of 31 zeros followed by a 1, but the zeros were not shown. This is probably a good thing.
Furthermore, the NOT operator uses two's complement, which means the number you get may be even stranger than you expect: using two's complement means that ~2 == -3. There are plenty of good explanations of two's complement online, so I won't go into that question here.
If what you want is just to reverse a string of bits without any interpretation, you can use a function like this:
function bitnot($bin)
{
$not = "";
for ($i = 0; $i < strlen($bin); $i++)
{
if($bin[$i] == 0) { $not .= '1'; }
if($bin[$i] == 1) { $not .= '0'; }
}
return $not;
}
It takes a binary string of any length, reverses the bits, and returns the new string. You can then treat it as a binary number, use bindec() to turn it into a decimal, or whatever you want.
I hope this helps someone as much as it would have helped me a week ago!