Наш Telegram бот: @htmlweb_bot
PHP: Побитовые операторы - Manual ScotlandPHP Conference 2019


    Операторы сравнения »
    « Оператор присваивания

    Edit Report a Bug

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

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

    Побитовые операторы
    Пример Название Результат
    $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 error_reporting использует побитовые значения, обеспечивая реальную демонстрацию удаления значений битов. Чтобы показать все ошибки, кроме замечаний, инструкции в файле php.ini предлагают использовать: <strong>E_ALL & ~E_NOTICE</strong>

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

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


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

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


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

    /*
     * Не обращайте внимания на этот верхний раздел кода,
     * это просто форматирование для более ясного вывода.
     */
    $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);
    }

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


    ---------- ----------- -- ----------
    результат значение оп тест
    ---------- ----------- -- ----------
    Побитовое И (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) над строками

    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 2 ^ "3"; // Выводит 1
                  // 2 ^ ((int)"3") == 1
    echo "2" ^ 3; // Выводит 1
                  // ((int)"2") ^ 3 == 1

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

    /*
     * Несколько примеров.
     */
    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 7.0 использование отрицательного побитового сдвига, либо сдвига, превышающегося разрядность операционной системы может привести к неопределенному результату. Другими словами, не сдвигайте больше чем на 31 бит на 32-битных системах и больше чем на 63 бита на 64-битных.

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


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


    # BitwiseFlag.php
    abstract class BitwiseFlag
    {
      protected $flags;
      /*
       * Note: these functions are protected to prevent outside code
       * from falsely setting BITS. See how the extending class 'User'
       * handles this.
       *
       */
      protected function isFlagSet($flag)
      {
        return (($this->flags & $flag) == $flag);
      }
      protected function setFlag($flag, $value)
      {
        if($value)
        {
          $this->flags |= $flag;
        }
        else
        {
          $this->flags &= ~$flag;
        }
      }
    }


    22
    grayda dot NOSPAM at DONTSPAM dot solidinc dot org10 years ago
        // The various details a vehicle can have
        $hasFourWheels = 1;
        $hasTwoWheels  = 2;
        $hasDoors      = 4;
        $hasRedColour  = 8;
        $bike          = $hasTwoWheels;
        $golfBuggy     = $hasFourWheels;
        $ford          = $hasFourWheels | $hasDoors;
        $ferrari       = $hasFourWheels | $hasDoors | $hasRedColour;
        $isBike        = $hasFourWheels & $bike; # False, because $bike doens't have four wheels
        $isGolfBuggy   = $hasFourWheels & $golfBuggy; # True, because $golfBuggy has four wheels
        $isFord        = $hasFourWheels & $ford; # True, because $ford $hasFourWheels


    5
    m0sh at hotmail dot com11 years ago
    function bitxor($str, $key) {
        $xorWidth = PHP_INT_SIZE*8;
        // split
        $o1 = str_split($str, $xorWidth);
        $o2 = str_split(str_pad('', strlen($str), $key), $xorWidth);
        $res = '';
        $runs = count($o1);
        for($i=0;$i<$runs;$i++)
            $res .= decbin(bindec($o1[$i]) ^ bindec($o2[$i]));       
        return $res;
    }


    7
    zooly at globmi dot com10 years ago
    function rotate ( $decimal, $bits) {
      $binary = decbin($decimal);
      return (
        bindec(substr($binary, $bits).substr($binary, 0, $bits))
      );
    }
    // Rotate 124 (1111100) to the left with 1 bits
    echo rotate(124, 1);
    // = 121 (1111001)
    // Rotate 124 (1111100) to the right with 3 bits
    echo rotate(124, -3);
    // = 79 (1001111)


    14
    14 years ago
        // We want to know the red, green and blue values of this color :
        $color = 0xFEA946 ;
        $red = $color >> 16 ;
        $green = ($color & 0x00FF00) >> 8 ;
        $blue = $color & 0x0000FF ;
        printf('Red : %X (%d), Green : %X (%d), Blue : %X (%d)',
            $red, $red, $green, $green, $blue, $blue) ;
        // Will display...
        // Red : FE (254), Green : A9 (169), Blue : 46 (70)


    8
    vivekanand dot pathak25 at gmail dot com6 years ago
    function unsigned_xor32 ($a, $b) 
    {
            $a1 = $a & 0x7FFF0000;
            $a2 = $a & 0x0000FFFF;
            $a3 = $a & 0x80000000;
            $b1 = $b & 0x7FFF0000;
            $b2 = $b & 0x0000FFFF;
            $b3 = $b & 0x80000000;
            $c = ($a3 != $b3) ? 0x80000000 : 0;
            return (($a1 ^ $b1) |($a2 ^ $b2)) + $c;
    }
    $x = 3851235679;
    $y = 43814;
    echo "<br />This is the value we want";
    echo "<br />3851262585";
    echo "<br />The result of a native xor operation on integer values is treated as a signed integer";
    echo "<br />".($x ^ $y);
    echo "<br />We therefore perform the MSB separately";
    echo "<br />".unsigned_xor32($x, $y);


    8
    Silver10 years ago
    define("f0", 0x1); // 2^0
    define("f1", 0x2); // 2^1
    define("f2", 0x4); // 2^2
    define("f3", 0x8); // 2^3
    define("f4", 0x10); // 2^4
    define("f5", 0x20); // 2^5
    // ...
    define("f20", 0x1000000); // 2^20
    define("f21", 0x2000000); // 2^21
    define("f22", 0x4000000); // 2^22
    define("f23", 0x8000000); // 2^23
    define("f24", 0x10000000); // 2^24
    // ... up to 2^31


    9
    frankemeks77 at yahoo dot com7 years ago
    echo 8 << 3; //64


    7
    zewt at hotmail dot com12 years ago
    echo masksOf(3,10);
    function masksOf($n,$bits) {
        $u = pow(2,$bits)-1; //start value, full flags on.
        $masks = array();
        while ($u>0) {
            $z = numflags($u);
            if ($z==$n) array_push($masks,$u);
            $u--;
        }
        return ($masks);    
    }
    function numflags($n) {
        $k = 0;
        while ($n) {
            $k += $n & 1;
            $n = $n >> 1;
        }
        return ($k);
    //    alternately: 
    //    $u = 0;
    //    for ($k=1;$k<=$n;$k*=2) {
    //        $u+=($n&$k?1:0);
    //    }
    //    return ($u);
    }


    3
    Eric Swanson14 years ago
    function circular_shift($num,$offset) { //Do a nondestructive circular bitwise shift, if offset positive shift left, if negative shift right
        $num=(int)$num;
        $mask=0x7fffffff; //Mask to cater for the fact that PHP only does arithmatic right shifts and not logical i.e. PHP doesn't give expected output when right shifting negative values
        if ($offset>0) {
            $num=($num<<$offset%32) | (($num>>(32-$offset%32)) & ($mask>>(31-$offset%32)));
        }
        elseif ($offset<0){
            $offset=abs($offset);
            $num=(($num>>$offset%32) & ($mask>>(-1+$offset%32))) | ($num<<(32-$offset%32));
        }
        return $num; 
    }


    3
    icy at digitalitcc dot com14 years ago
    /*
        Infinite* bits and bit handling in general.
        
        *Not infinite, sorry.
        
        Perceivably, the only limit to the bitmask class in storing bits would be
        the maximum limit of the index number, on 32 bit integer systems 2^31 - 1,
        so 2^31 * 31 - 1 = 66571993087 bits, assuming floats are 64 bit or something.
        I'm sure that's enough enough bits for anything.. I hope :D.
    */
    DEFINE('INTEGER_LENGTH',31); // Stupid signed bit.
    class bitmask
    {
        protected $bitmask = array();
        
        public function set( $bit ) // Set some bit
        {
            $key = (int) ($bit / INTEGER_LENGTH);
            $bit = (int) fmod($bit,INTEGER_LENGTH);
            $this->bitmask[$key] |= 1 << $bit;
        }
        
        public function remove( $bit ) // Remove some bit
        {
            $key = (int) ($bit / INTEGER_LENGTH);
            $bit = (int) fmod($bit,INTEGER_LENGTH);
            $this->bitmask[$key] &= ~ (1 << $bit);
            if(!$this->bitmask[$key])
                unset($this->bitmask[$key]);
        }
        
        public function toggle( $bit ) // Toggle some bit
        {
            $key = (int) ($bit / INTEGER_LENGTH);
            $bit = (int) fmod($bit,INTEGER_LENGTH);
            $this->bitmask[$key] ^= 1 << $bit;
            if(!$this->bitmask[$key])
                unset($this->bitmask[$key]);
        }
        
        public function read( $bit ) // Read some bit
        {
            $key = (int) ($bit / INTEGER_LENGTH);
            $bit = (int) fmod($bit,INTEGER_LENGTH);
            return $this->bitmask[$key] & (1 << $bit);
        }
        public function stringin($string) // Read a string of bits that can be up to the maximum amount of bits long.
        {
            $this->bitmask = array();
            $array = str_split( strrev($string), INTEGER_LENGTH );
            foreach( $array as $key => $value )
            {
                if($value = bindec(strrev($value)))
                    $this->bitmask[$key] = $value;
            }
        }
        public function stringout() // Print out a string of your nice little bits
        {
            $string = "";
            $keys = array_keys($this->bitmask);
            sort($keys, SORT_NUMERIC);
            for($i = array_pop($keys);$i >= 0;$i--)
            {
                if($this->bitmask[$i])
                    $string .= sprintf("%0" . INTEGER_LENGTH . "b",$this->bitmask[$i]);
            }
            return $string;
        }
        
        public function clear() // Purge!
        {
            $this->bitmask = array();
        }
        
        public function debug() // See what's going on in your bitmask array
        {
            var_dump($this->bitmask);
        }
    }


    1
    forlamp at msn dot com11 years ago
    if (('18' & '32') == '10') {
        echo ord('18'); //return decimal value 49, which have binary value 110001
        echo ord('32'); //return decimal value 51, which have binary value 110011
        echo ord('10'); //return decimal value 49, which have binary value 110001
        //Therefore 110001 & 110011 = 110001
    }


    4
    ivoras at gmail dot com8 years ago
    $foo = "1"; // chr(49)
    var_dump($foo << 1); // Output is int(2)
    $foo = "!"; // chr(33)
    var_dump($foo << 1); // Output is int(0)


    2
    Tbrendstrup14 years ago
    function lshiftright($var,$amt)
    {
        $mask = 0x40000000;
        if($var < 0)
        {
            $var &= 0x7FFFFFFF;
            $mask = $mask >> ($amt-1);
            return ($var >> $amt) | $mask;
        }
        return $var >> $amt;
    }
    $val = -10;
    printf("arithmetic shift on a negative integer<br />%1\$032b<br />%2\$032b<br />%1\$0d<br />%2\$0d<br />",$val, $val >> 1 );
    printf("logic shift on a negative integer<br />%1\$032b<br />%2\$032b<br />%1\$0d<br />%2\$0d<br />",$val, lshiftright($val, 1));
    printf("logic shift on a positive integer<br />%1\$032b<br />%2\$032b<br />%1\$0d<br />%2\$0d<br />",-$val, lshiftright(-$val, 1));


    1
    Core Xii9 years ago
    var_dump(1234 ^ 0); // int(1234)
    var_dump(1234 ^ ''); // int(1234)
    var_dump(1234 ^ null); // int(1234)
    var_dump('hello world' ^ 0); // int(0)
    var_dump('hello world' ^ ''); // string(0) ""
    var_dump('hello world' ^ null); // int(0)


    1
    Adam9 years ago
    if ($x & 2 == 2) {
        /* code */
    }


    1
    Anonymous8 years ago
    function count_set_bits( $n ){
      if( $n >= 0 ){  for( $count = 0;  $n;       ++$count )  $n &= $n - 1;  }
               else{  for( $count = 1;  $n << 1;  ++$count )  $n &= $n - 1;  }
      return $count;
    }
    echo 'This PHP uses ' . count_set_bits(-1) .'-bit integers.';


    0
    ASchmidt at Anamera dot net2 months ago
        const    FLAG_A    =    0b0001,
                FLAG_B    =    0b0010,
                FLAG_C    =    0b0100,
                FLAG_D    =    0b1000;
                
        const    COMBO_BC = FLAG_B | FLAG_C;
        $bitmask = 0b000;
        
        // Setting individual flags.
        $bitmask |=    FLAG_B;        // Sets FLAG_B (=2)
        $bitmask |=    FLAG_C;        // also sets FLAG_C (=4)
        
        // Testing single or multiple flags.
        echo (bool)( $bitmask & FLAG_B );                            // True, B is set.
        
        echo (bool)( $bitmask & (FLAG_A | FLAG_B) );                // True, A or B is set.
        
        echo (bool)( $bitmask & FLAG_B and $bitmask & FLAG_C );        // True, B and C are set.
        echo (bool)( ( $bitmask & (FLAG_B | FLAG_C) ) ^ (FLAG_B | FLAG_C) );    // False if B and C are set.
        echo (bool)( ( $bitmask & COMBO_BC ) ^ COMBO_BC );            // False if B and C are set.
        
        echo (bool)( $bitmask & FLAG_C and $bitmask & FLAG_D );        // False, C and D are NOT BOTH set.
        echo (bool)( ( $bitmask & (FLAG_C | FLAG_D) ) ^ (FLAG_C | FLAG_D) );    // True, if C and D are NOT BOTH set.
        
        // Resetting single flag.
        $bitmask &= $bitmask ^ FLAG_B;    // Unsets B
        $bitmask &= $bitmask ^ FLAG_A;    // A remains unset.
        var_dump( $bitmask );            // Only C still set (=4)
        
        // Resetting multiple flags.
        $bitmask &= $bitmask ^ ( FLAG_C | FLAG_D );    // Unsets C and/or D
        var_dump( $bitmask );            // No flags set (=0) 
     
    0 
     joey ¶3 years ago
     If you want a quick one liner for reversing binary and performance/sanity isn't an issue:
        function reverse_bits($n) {
            return (int)base_convert(strrev(str_pad(base_convert($n, 10, 2), PHP_INT_SIZE * 8, 0, STR_PAD_LEFT)), 2, 10);
        }
    Expect it to behave strangely for the signed bit. Best to use for < PHP_INT_SIZE * 8 to avoid peculiarity. You can also skip the cast if you don't mind keeping your number as a string. base convert appears to work for large precision or perhaps arbitrary but be prepared for strangeness (double, mixed types, precision loss, etc) if you need to work on the revolting number.
    Use at your own peril. 
     
    0 
     luis at rosety dot com ¶4 years ago
     Example of function using bitwise operations for converting hexadecimal color (usually given as 6 hexadecimal digit string, into separated RGB integers)
    <?php
    function hex2rgb($hex){
        $dec = hexdec($hexcolor);               // $hex string to decimal value
        $r = $dec & hexdec('FF0000');          //Mask for red
        $g = $dec & hexdec('00FF00');         //Mask for green
        $b = $dec & hexdec('0000FF');         //Mask for blue
        return array($r>>16, $g>>8, $b);       // Shift full right each color from its original position 
    }


    0
    J. Ketting5 years ago
    function rotate ($decimal, $bits) {
      $binary = decbin($decimal);
      $binary = str_pad($binary, 32, '0', STR_PAD_LEFT);
      return (
        bindec(substr($binary, $bits).substr($binary, 0, $bits))
      );
    }


    0
    Bob10 years ago
    function set_bitflag(/*variable-length args*/)
    {
        $val = 0;
        foreach(func_get_args() as $flag) $val = $val | $flag;
        return $val;
    }
    function is_bitflag_set($val, $flag)
    {
        return (($val & $flag) === $flag);
    }
    // Define your flags
    define('MYFLAGONE', 1); // 0001
    define('MYFLAGTWO', 2); // 0010
    define('MYFLAGTHREE', 4); // 0100
    define('MYFLAGFOUR', 8); // 1000


    0
    bartbons at debster.nl11 years ago
    function bitRotate32($value,$amount) {
        if ($amount>0) {
            $amount %= 32;
            $value = ($value<<$amount) | ($value>>(32-$amount));
        } elseif ($amount<0) {
            $amount = -$amount%32;
            $value = ($value>>$amount) | ($value<<(32-$amount));
        }
        return $value;
    }
    function bitRotate($value,$amount,$bits) {
        $mask = ($bits<32) ? 0x7fffffff >> (31-$bits) : 0xffffffff;
        if ($amount>0) {
            $amount %= $bits;
            $value = ($value<<$amount) | ($value>>($bits-$amount));
        } elseif ($amount<0) {
            $amount = -$amount%$bits;
            $value = ($value>>$amount) | ($value<<($bits-$amount));
        }
        return $value & $mask;
    }
    // test the rotation:
    $test = 4123;
    for ($i=0; $i<64; $i++) {
        $value = bitRotate($test,-$i,8); // rotates 8 bits to the left (-$amount)
        echo sprintf("%032b<br/>",$value);
    }


    Описание на ru2.php.net
    Описание на php.ru