按位運算子

字首按位運算子

按位運算子類似於邏輯運算子,但按位而不是每布林值執行。

// bitwise NOT ~: sets all unset bits and unsets all set bits
printf("%'06b", ~0b110110); // 001001

位掩碼位掩碼運算子

按位 AND &:只有在兩個運算元中都設定了一個位

printf("%'06b", 0b110101 & 0b011001); // 010001

按位 OR |:如果在一個或兩個運算元中設定了一個位

printf("%'06b", 0b110101 | 0b011001); // 111101

Bitwise XOR ^:如果在一個運算元中設定並且未在另一個運算元中設定,則設定為位,即僅在該運算元中該位處於不同狀態時

printf("%'06b", 0b110101 ^ 0b011001); // 101100

位掩碼的示例用法

這些運算子可用於操作位掩碼。例如:

file_put_contents("file.log", LOCK_EX | FILE_APPEND);

這裡,|運算子用於組合兩個位掩碼。儘管+具有相同的效果,但|強調你正在組合位掩碼,而不是新增兩個正常的標量整數。

class Foo{
    const OPTION_A = 1;
    const OPTION_B = 2;
    const OPTION_C = 4;
    const OPTION_A = 8;

    private $options = self::OPTION_A | self::OPTION_C;

    public function toggleOption(int $option){
        $this->options ^= $option;
    }

    public function enable(int $option){
        $this->options |= $option; // enable $option regardless of its original state
    }

    public function disable(int $option){
        $this->options &= ~$option; // disable $option regardless of its original state,
                                    // without affecting other bits
    }

    /** returns whether at least one of the options is enabled */
    public function isOneEnabled(int $options) : bool{
        return $this->options & $option !== 0;
        // Use !== rather than >, because 
        // if $options is about a high bit, we may be handling a negative integer
    }

    /** returns whether all of the options are enabled */
    public function areAllEnabled(int $options) : bool{
        return ($this->options & $options) === $options;
        // note the parentheses; beware the operator precedence
    }
}

此示例(假設 $option 始終只包含一位)使用:

  • ^操作符可以方便地切換位掩碼。
  • |運算子設定一個忽略其原始狀態或其他位的位
  • ~運算子將只有一位設定的整數轉換為只有一位未設定的整數
  • 使用 & 的這些屬性,& 運算子取消設定:
    • 由於具有設定位的 &= 將不會執行任何操作((1 & 1) === 1(0 & 1) === 0),因此使用僅未設定一位的整數執行 &= 將僅取消設定該位,而不會影響其他位。
    • 未設定位的 &= 將取消該位((1 & 0) === 0(0 & 0) === 0
  • & 運算子與另一個位掩碼一起使用將過濾掉該位掩碼中未設定的所有其他位。
    • 如果輸出設定了任何位,則表示啟用了任何一個選項。
    • 如果輸出具有位掩碼集的所有位,則表示位掩碼中的所有選項都已啟用。

請記住,這些比較運算子:(< > <= >= == === != !== <> <=>)具有比這些位掩碼位掩碼運算子更高的優先順序:( | ^ &)。由於使用這些比較運算子經常比較逐位結果,因此這是一個常見的陷阱。

位移運算子

按位左移 <<:按給定的步數將所有位向左移位(更重要)並丟棄超過 int 大小的位

<< $x 相當於取消最高的 $x 位並乘以 $xth 的 2 次冪

printf("%'08b", 0b00001011<< 2); // 00101100

assert(PHP_INT_SIZE === 4); // a 32-bit system
printf("%x, %x", 0x5FFFFFFF << 2, 0x1FFFFFFF << 4); // 7FFFFFFC, FFFFFFFF

按位右移 >>:丟棄最低位移並將剩餘位向右移位(不太重要)

>> $x 相當於除以 2 的 $x 次冪並丟棄非整數部分

printf("%x", 0xFFFFFFFF >> 3); // 1FFFFFFF

位移的示例用法:

快速除以 16(效能比/= 16 更好)

$x >>= 4;

在 32 位系統上,這將丟棄整數中的所有位,將該值設定為 0.在 64 位系統上,這將取消設定最重要的 32 位並保持最少

$x = $x << 32 >> 32;

顯著的 32 位,相當於 $x & 0xFFFFFFFF

注意:在此示例中,使用了 printf("%'06b")。它以 6 位二進位制數字輸出值。