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

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

Побитовые операторы
ПримерНазваниеРезультат
$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 всех символов строки и в результате вернёт строку, иначе как операнд, так и результат, будут считаться целыми.

И операнды, и результат выполнения операторов << и >> рассматриваются как целые числа.

 В PHP ini-настройка 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 через оператор ИЛИ (|), чтобы получить биты, установленные хотя бы в одном операнде: 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(0, 1, 2, 4, 8);
$test = 1 + 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);
}

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

 --------- --------- -- --------- result value op test --------- --------- -- --------- Побитовое И ( 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) Побитовое ИЛИ ( 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)

Пример #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 ЗАМЕЧАНИЕ: биты были выдвинуты за левый край, включая знаковый бит 
Внимание

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

To Top