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

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

Побитовые операторы
Пример | Название | Результат
--- | --- | ---
`$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);
    }

    ?>

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

     ---------     ---------  -- ---------
     Результат     Значение   Тестовая операция
     ---------     ---------  -- ---------
     Побитовое И
    ( 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, PHP_EOL; // Выводит '5'

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

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

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

    echo "2" ^ 3, PHP_EOL; // Выводит 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\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.

### Смотрите также

- pack()
- unpack()
- gmp_and()
- gmp_or()
- gmp_xor()
- gmp_testbit()
- gmp_clrbit()

`↑` and `↓` to navigate • `Enter` to select • `Esc` to close • `/` to open