Побитовые операторы


Побитовые операторы позволяют считывать и устанавливать конкретные биты целых чисел.

Побитовые операторы
Пример Название Результат
$a & $b И Устанавливаются только те биты, которые установлены и в $a, и в $b.
$a | $b Или Устанавливаются те биты, которые установлены в $a или в $b.
$a ^ $b Исключающее или Устанавливаются только те биты, которые установлены либо только в $a, либо только в $b, но не в обоих одновременно.
~ $a Отрицание Устанавливаются те биты, которые не установлены в $a, и наоборот.
$a << $b Сдвиг влево Все биты переменной $a сдвигаются на $b позиций влево (каждая позиция подразумевает "умножение на 2")
$a >> $b Сдвиг вправо Все биты переменной $a сдвигаются на $b позиций вправо (каждая позиция подразумевает "деление на 2")

Побитовый сдвиг в PHP - это арифметическая операция. Биты, сдвинутые за границы числа, отбрасываются. Сдвиг влево дополняет число нулями справа, сдвигая в то же время знаковый бит числа влево, что означает что знак операнда не сохраняется. Сдвиг вправо сохраняет копию сдвинутого знакового бита слева, что означает что знак операнда сохраняется.

Используйте скобки для обеспечения необходимого приоритета операторов. Например, $a & $b == true сначала проверяет на равенство, а потом выполняет побитовое и; тогда как ($a & $b) == true сначала выполняет побитовое и, а потом выполняет проверку на равенство.

Если оба операнда для &, | и ^ являются строками, то операция будет выполнена над ASCII значениями символов, составляющих эти строки, и результатом будет строка. В других случаях, оба операнда будут приведены к целому и результатом будет тоже целое число.

Если операнд для оператора ~ является строкой, то операция будет произведена над ASCII значением символов, состовляющих эту строку, и результатом будет строка. Иначе, и операнд и результат будут оперироваться как целые числа.

Both operands and the result for the << and >> operators are always treated as integers.

        Опция настроек PHP error_reporting использует побитовые значения,        обеспечивая реальную демонстрацию гашения значений битов.        Чтобы показать все ошибки кроме замечаний,        инструкции в файле php.ini предлагают использовать:        E_ALL & ~E_NOTICE       

        Начинаем со значения E_ALL:        00000000000000000111011111111111        Затем берем значение E_NOTICE...        00000000000000000000000000001000        ... и инвертируем его с помощью ~:        11111111111111111111111111110111        Наконец, используем побитовое И (&), чтобы установить только те биты,        которые установлены в единицу в обоих значениях:        00000000000000000111011111110111       

        Другой способ достичь этого - использовать ИСКЛЮЧАЮЩЕЕ ИЛИ (XOR, ^),        чтобы получить только те биты, которые установлены в единицу        либо только в одном, либо только в другом значении:        E_ALL ^ E_NOTICE       

        Опция error_reporting также может быть использована для демонстрации        установки битов. Показать только ошибки и обрабатываемые ошибки можно        следующим образом:        E_ERROR | E_RECOVERABLE_ERROR       

        Здесь мы комбинируем E_ERROR        00000000000000000000000000000001        и        00000000000000000001000000000000        с помощью оператора ИЛИ (OR, |),        чтобы получить биты, установленные хотя бы в одном операнде:        00000000000000000001000000000001       

Пример #1 Побитовыми операции И, ИЛИ и ИСКЛЮЧАЮЩЕЕ ИЛИ (AND, OR и XOR) над целыми числами

<?php
/*
 * Не обращайте внимания на этот верхний раздел кода,
 * это просто форматирование для более ясного вывода.
 */

$format '(%1$2d = %1$04b) = (%2$2d = %2$04b)'
        
' %3$s (%4$2d = %4$04b)' "\n";

echo <<<EOH
 ---------     ---------  -- ---------
 результат     значение   оп   тест
 ---------     ---------  -- ---------
EOH;


/*
 * Вот сами примеры.
 */

$values = array(01248);
$test 4;

echo 
"\n Побитовое И (AND) \n";
foreach (
$values as $value) {
    
$result $value $test;
    
printf($format$result$value'&'$test);
}

echo 
"\n Побитовое (включающее) ИЛИ (OR) \n";
foreach (
$values as $value) {
    
$result $value $test;
    
printf($format$result$value'|'$test);
}

echo 
"\n Побитовое ИСКЛЮЧАЮЩЕЕ ИЛИ (XOR) \n";
foreach (
$values as $value) {
    
$result $value $test;
    
printf($format$result$value'^'$test);
}
?>

Результат выполнения данного примера:

  ---------     ---------  -- ---------  результат     значение   оп   тест  ---------     ---------  -- ---------  Побитовое И (AND) ( 0 = 0000) = ( 0 = 0000) & ( 5 = 0101) ( 1 = 0001) = ( 1 = 0001) & ( 5 = 0101) ( 0 = 0000) = ( 2 = 0010) & ( 5 = 0101) ( 4 = 0100) = ( 4 = 0100) & ( 5 = 0101) ( 0 = 0000) = ( 8 = 1000) & ( 5 = 0101)   Побитовое (включающее) ИЛИ (OR) ( 5 = 0101) = ( 0 = 0000) | ( 5 = 0101) ( 5 = 0101) = ( 1 = 0001) | ( 5 = 0101) ( 7 = 0111) = ( 2 = 0010) | ( 5 = 0101) ( 5 = 0101) = ( 4 = 0100) | ( 5 = 0101) (13 = 1101) = ( 8 = 1000) | ( 5 = 0101)   Побитовое ИСКЛЮЧАЮЩЕЕ ИЛИ (XOR) ( 5 = 0101) = ( 0 = 0000) ^ ( 5 = 0101) ( 4 = 0100) = ( 1 = 0001) ^ ( 5 = 0101) ( 7 = 0111) = ( 2 = 0010) ^ ( 5 = 0101) ( 1 = 0001) = ( 4 = 0100) ^ ( 5 = 0101) (13 = 1101) = ( 8 = 1000) ^ ( 5 = 0101) 

Пример #2 Побитовая операция ИСКЛЮЧАЮЩЕЕ ИЛИ (XOR) над строками

<?php
echo 12 9// Выводит '5'

echo "12" "9"// Выводит символ Backspace (ascii 8)
                 // ('1' (ascii 49)) ^ ('9' (ascii 57)) = #8

echo "hallo" "hello"// Выводит ascii значения #0 #4 #0 #0 #0
                        // 'a' ^ 'e' = #4

echo "3"// Выводит 1
              // 2 ^ ((int)"3") == 1

echo "2" 3// Выводит 1
              // ((int)"2") ^ 3 == 1
?>

Пример #3 Побитовый сдвиг над целыми числами

<?php
/*
 * Несколько примеров.
 */

echo "\n--- СДВИГ ВПРАВО НАД ПОЛОЖИТЕЛЬНЫМИ ЦЕЛЫМИ ЧИСЛАМИ ---\n";

$val 4;
$places 1;
$res $val >> $places;
p($res$val'>>'$places'слева была вставлена копия знакового бита');

$val 4;
$places 2;
$res $val >> $places;
p($res$val'>>'$places);

$val 4;
$places 3;
$res $val >> $places;
p($res$val'>>'$places'биты были выдвинуты за правый край');

$val 4;
$places 4;
$res $val >> $places;
p($res$val'>>'$places'то же, что и выше; нельзя сдвинуть дальше 0');


echo 
"\n--- СДВИГ ВПРАВО НАД ОТРИЦАТЕЛЬНЫМИ ЦЕЛЫМИ ЧИСЛАМИ ---\n";

$val = -4;
$places 1;
$res $val >> $places;
p($res$val'>>'$places'слева была вставлена копия знакового бита');

$val = -4;
$places 2;
$res $val >> $places;
p($res$val'>>'$places'биты были выдвинуты за правый край');

$val = -4;
$places 3;
$res $val >> $places;
p($res$val'>>'$places'то же, что и выше; нельзя сдвинуть дальше -1');


echo 
"\n--- СДВИГ ВЛЕВО НАД ПОЛОЖИТЕЛЬНЫМИ ЦЕЛЫМИ ЧИСЛАМИ ---\n";

$val 4;
$places 1;
$res $val << $places;
p($res$val'<<'$places'правый край был дополнен нулями');

$val 4;
$places = (PHP_INT_SIZE 8) - 4;
$res $val << $places;
p($res$val'<<'$places);

$val 4;
$places = (PHP_INT_SIZE 8) - 3;
$res $val << $places;
p($res$val'<<'$places'знаковые биты были выдвинуты');

$val 4;
$places = (PHP_INT_SIZE 8) - 2;
$res $val << $places;
p($res$val'<<'$places'биты были выдвинуты за левый край');


echo 
"\n--- СДВИГ ВЛЕВО НАД ОТРИЦАТЕЛЬНЫМИ ЦЕЛЫМИ ЧИСЛАМИ ---\n";

$val = -4;
$places 1;
$res $val << $places;
p($res$val'<<'$places'правый край был дополнен нулями');

$val = -4;
$places = (PHP_INT_SIZE 8) - 3;
$res $val << $places;
p($res$val'<<'$places);

$val = -4;
$places = (PHP_INT_SIZE 8) - 2;
$res $val << $places;
p($res$val'<<'$places'биты были выдвинуты за левый край, включая знаковый бит');


/*
 * Не обращайте внимания на этот нижний раздел кода,
 * это просто форматирование для более ясного вывода.
 */

function p($res$val$op$places$note '') {
    
$format '%0' . (PHP_INT_SIZE 8) . "b\n";

    
printf("Выражение: %d = %d %s %d\n"$res$val$op$places);

    echo 
" Десятичный вид:\n";
    
printf("  val=%d\n"$val);
    
printf("  res=%d\n"$res);

    echo 
" Двоичный вид:\n";
    
printf('  val=' $format$val);
    
printf('  res=' $format$res);

    if (
$note) {
        echo 
" ЗАМЕЧАНИЕ: $note\n";
    }

    echo 
"\n";
}
?>

Результат выполнения данного примера на 32-битных машинах:

  --- СДВИГ ВПРАВО НАД ПОЛОЖИТЕЛЬНЫМИ ЦЕЛЫМИ ЧИСЛАМИ --- Выражение: 2 = 4 >> 1  Десятичный вид:   val=4   res=2  Двоичный вид:   val=00000000000000000000000000000100   res=00000000000000000000000000000010  ЗАМЕЧАНИЕ: слева была вставлена копия знакового бита   Выражение: 1 = 4 >> 2  Десятичный вид:   val=4   res=1  Двоичный вид:   val=00000000000000000000000000000100   res=00000000000000000000000000000001  Выражение: 0 = 4 >> 3  Десятичный вид:   val=4   res=0  Двоичный вид:   val=00000000000000000000000000000100   res=00000000000000000000000000000000  ЗАМЕЧАНИЕ: биты были выдвинуты за правый край  Выражение: 0 = 4 >> 4  Десятичный вид:   val=4   res=0  Двоичный вид:   val=00000000000000000000000000000100   res=00000000000000000000000000000000  ЗАМЕЧАНИЕ: то же, что и выше; нельзя сдвинуть дальше 0   --- СДВИГ ВПРАВО НА ОТРИЦАТЕЛЬНЫХ ЦЕЛЫХ ЧИСЛАХ --- Выражение: -2 = -4 >> 1  Десятичный вид:   val=-4   res=-2  Двоичный вид:   val=11111111111111111111111111111100   res=11111111111111111111111111111110  ЗАМЕЧАНИЕ: слева была вставлена копия знакового бита  Выражение: -1 = -4 >> 2  Десятичный вид:   val=-4   res=-1  Двоичный вид:   val=11111111111111111111111111111100   res=11111111111111111111111111111111  ЗАМЕЧАНИЕ: биты были выдвинуты за правый край  Выражение: -1 = -4 >> 3  Десятичный вид:   val=-4   res=-1  Двоичный вид:   val=11111111111111111111111111111100   res=11111111111111111111111111111111  ЗАМЕЧАНИЕ: то же, что и выше; нельзя сдвинуть дальше -1   --- СДВИГ ВЛЕВО НАД ПОЛОЖИТЕЛЬНЫМИ ЦЕЛЫМИ ЧИСЛАМИ --- Выражение: 8 = 4 << 1  Десятичный вид:   val=4   res=8  Двоичный вид:   val=00000000000000000000000000000100   res=00000000000000000000000000001000  ЗАМЕЧАНИЕ: правый край был дополнен нулями  Выражение: 1073741824 = 4 << 28  Десятичный вид:   val=4   res=1073741824  Двоичный вид:   val=00000000000000000000000000000100   res=01000000000000000000000000000000  Выражение: -2147483648 = 4 << 29  Десятичный вид:   val=4   res=-2147483648  Двоичный вид:   val=00000000000000000000000000000100   res=10000000000000000000000000000000  ЗАМЕЧАНИЕ: знаковые биты были выдвинуты  Выражение: 0 = 4 << 30  Десятичный вид:   val=4   res=0  Двоичный вид:   val=00000000000000000000000000000100   res=00000000000000000000000000000000  ЗАМЕЧАНИЕ: биты были выдвинуты за левый край   --- СДВИГ ВЛЕВО НАД ОТРИЦАТЕЛЬНЫМИ ЦЕЛЫМИ ЧИСЛАМИ --- Выражение: -8 = -4 << 1  Десятичный вид:   val=-4   res=-8  Двоичный вид:   val=11111111111111111111111111111100   res=11111111111111111111111111111000  ЗАМЕЧАНИЕ: правый край был дополнен нулями  Выражение: -2147483648 = -4 << 29  Десятичный вид:   val=-4   res=-2147483648  Двоичный вид:   val=11111111111111111111111111111100   res=10000000000000000000000000000000  Выражение: 0 = -4 << 30  Десятичный вид:   val=-4   res=0  Двоичный вид:   val=11111111111111111111111111111100   res=00000000000000000000000000000000  ЗАМЕЧАНИЕ: биты были выдвинуты за левый край, включая знаковый бит 

Результат выполнения данного примера на 64-битных машинах:

  --- СДВИГ ВПРАВО НАД ПОЛОЖИТЕЛЬНЫМИ ЦЕЛЫМИ ЧИСЛАМИ --- Выражение: 2 = 4 >> 1  Десятичный вид:   val=4   res=2  Двоичный вид:   val=0000000000000000000000000000000000000000000000000000000000000100   res=0000000000000000000000000000000000000000000000000000000000000010  ЗАМЕЧАНИЕ: слева была вставлена копия знакового бита  Выражение: 1 = 4 >> 2  Десятичный вид:   val=4   res=1  Двоичный вид:   val=0000000000000000000000000000000000000000000000000000000000000100   res=0000000000000000000000000000000000000000000000000000000000000001  Выражение: 0 = 4 >> 3  Десятичный вид:   val=4   res=0  Двоичный вид:   val=0000000000000000000000000000000000000000000000000000000000000100   res=0000000000000000000000000000000000000000000000000000000000000000  ЗАМЕЧАНИЕ: биты были выдвинуты за правый край  Выражение: 0 = 4 >> 4  Десятичный вид:   val=4   res=0  Двоичный вид:   val=0000000000000000000000000000000000000000000000000000000000000100   res=0000000000000000000000000000000000000000000000000000000000000000  ЗАМЕЧАНИЕ: то же, что и выше; нельзя сдвинуть дальше 0   --- СДВИГ ВПРАВО НАД ОТРИЦАТЕЛЬНЫМИ ЦЕЛЫМИ ЧИСЛАМИ --- Выражение: -2 = -4 >> 1  Десятичный вид:   val=-4   res=-2  Двоичный вид:   val=1111111111111111111111111111111111111111111111111111111111111100   res=1111111111111111111111111111111111111111111111111111111111111110  ЗАМЕЧАНИЕ: слева была вставлена копия знакового бита  Выражение: -1 = -4 >> 2  Десятичный вид:   val=-4   res=-1  Двоичный вид:   val=1111111111111111111111111111111111111111111111111111111111111100   res=1111111111111111111111111111111111111111111111111111111111111111  ЗАМЕЧАНИЕ: биты были выдвинуты за правый край  Выражение: -1 = -4 >> 3  Десятичный вид:   val=-4   res=-1  Двоичный вид:   val=1111111111111111111111111111111111111111111111111111111111111100   res=1111111111111111111111111111111111111111111111111111111111111111  ЗАМЕЧАНИЕ: то же, что и выше; нельзя сдвинуть дальше -1   --- СДВИГ ВЛЕВО НАД ПОЛОЖИТЕЛЬНЫМИ ЦЕЛЫМИ ЧИСЛАМИ --- Выражение: 8 = 4 << 1  Десятичный вид:   val=4   res=8  Двоичный вид:   val=0000000000000000000000000000000000000000000000000000000000000100   res=0000000000000000000000000000000000000000000000000000000000001000  ЗАМЕЧАНИЕ: правый край был дополнен нулями  Выражение: 4611686018427387904 = 4 << 60  Десятичный вид:   val=4   res=4611686018427387904  Двоичный вид:   val=0000000000000000000000000000000000000000000000000000000000000100   res=0100000000000000000000000000000000000000000000000000000000000000  Выражение: -9223372036854775808 = 4 << 61  Десятичный вид:   val=4   res=-9223372036854775808  Двоичный вид:   val=0000000000000000000000000000000000000000000000000000000000000100   res=1000000000000000000000000000000000000000000000000000000000000000  ЗАМЕЧАНИЕ: знаковые биты были выдвинуты  Выражение: 0 = 4 << 62  Десятичный вид:   val=4   res=0  Двоичный вид:   val=0000000000000000000000000000000000000000000000000000000000000100   res=0000000000000000000000000000000000000000000000000000000000000000  ЗАМЕЧАНИЕ: биты были выдвинуты за левый край   --- СДВИГ ВЛЕВО НАД ОТРИЦАТЕЛЬНЫМИ ЦЕЛЫМИ ЧИСЛАМИ --- Выражение: -8 = -4 << 1  Десятичный вид:   val=-4   res=-8  Двоичный вид:   val=1111111111111111111111111111111111111111111111111111111111111100   res=1111111111111111111111111111111111111111111111111111111111111000  ЗАМЕЧАНИЕ: правый край был дополнен нулями  Выражение: -9223372036854775808 = -4 << 61  Десятичный вид:   val=-4   res=-9223372036854775808  Двоичный вид:   val=1111111111111111111111111111111111111111111111111111111111111100   res=1000000000000000000000000000000000000000000000000000000000000000  Выражение: 0 = -4 << 62  Десятичный вид:   val=-4   res=0  Двоичный вид:   val=1111111111111111111111111111111111111111111111111111111111111100   res=0000000000000000000000000000000000000000000000000000000000000000  ЗАМЕЧАНИЕ: биты были выдвинуты за левый край, включая знаковый бит 

Внимание

Сдвиг целых чисел на значение, большее или равное максимальной ширине целых целых чисел в системе будет приводить к неопределенному поведению. Другими словами, не производите сдвиг больше чем на 31 в 32-битных платформах, и 63 в 64-битных.

Используйте функции из расширения gmp для двоичных операций над числами больше PHP_INT_MAX.

Смотрите также pack(), unpack(), gmp_and(), gmp_or(), gmp_xor(), gmp_testbit(), gmp_clrbit()