演算子
PHP Manual

ビット演算子

ビット演算子は、整数値の特定のビットの評価や操作を行います。

ビット演算子
名前 結果
$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 コードで演算を行います。

PHP の ini 設定 error_reporting はビット値を用いています。
これを用いて、特定のビットを落とす演算の例を見てみましょう。
notice 以外のすべてのエラーを表示させるには、
php.ini ファイルで
E_ALL & ~E_NOTICE

と指定することになります。
      

まずは E_ALL。
00000000000000000111011111111111
そして E_NOTICE...。
00000000000000000000000000001000
... これを ~ で逆転させます。
11111111111111111111111111110111
最後に AND (&) を使い、両方ともビットが立っているところをみつけます。
00000000000000000111011111110111
      

同じ結果を得るもうひとつの方法として、 XOR (^)
を使ってどちらか一方だけ立っているビットを探すという方法もあります。
E_ALL ^ E_NOTICE

      

error_reporting を使って、特定のビットを立てる処理の例を見てみましょう。
通常のエラーとリカバー可能なエラーだけを表示させるには、次のようにします。
E_ERROR | E_RECOVERABLE_ERROR

      

この処理は、 E_ERROR
0000000000000000000000000000000100000000000000000001000000000000
を 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
 ---------     ---------  -- ---------
 result        value      op test
 ---------     ---------  -- ---------
EOH;


/*
 * ここからが本番
 */

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

echo 
"\n Bitwise AND \n";
foreach (
$values as $value) {
    
$result $value $test;
    
printf($format$result$value'&'$test);
}

echo 
"\n Bitwise Inclusive OR \n";
foreach (
$values as $value) {
    
$result $value $test;
    
printf($format$result$value'|'$test);
}

echo 
"\n Bitwise Exclusive OR (XOR) \n";
foreach (
$values as $value) {
    
$result $value $test;
    
printf($format$result$value'^'$test);
}
?>

上の例の出力は以下となります。

 ---------     ---------  -- ---------
 result        value      op test
 ---------     ---------  -- ---------
 Bitwise 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)

 Bitwise Inclusive 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)

 Bitwise Exclusive OR (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"// 出力はバックスペース文字 (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--- BIT SHIFT RIGHT ON POSITIVE INTEGERS ---\n";

$val 4;
$places 1;
$res $val >> $places;
p($res$val'>>'$places'copy of sign bit shifted into left side');

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

$val 4;
$places 3;
$res $val >> $places;
p($res$val'>>'$places'bits shift out right side');

$val 4;
$places 4;
$res $val >> $places;
p($res$val'>>'$places'same result as above; can not shift beyond 0');


echo 
"\n--- BIT SHIFT RIGHT ON NEGATIVE INTEGERS ---\n";

$val = -4;
$places 1;
$res $val >> $places;
p($res$val'>>'$places'copy of sign bit shifted into left side');

$val = -4;
$places 2;
$res $val >> $places;
p($res$val'>>'$places'bits shift out right side');

$val = -4;
$places 3;
$res $val >> $places;
p($res$val'>>'$places'same result as above; can not shift beyond -1');


echo 
"\n--- BIT SHIFT LEFT ON POSITIVE INTEGERS ---\n";

$val 4;
$places 1;
$res $val << $places;
p($res$val'<<'$places'zeros fill in right side');

$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'sign bits get shifted out');

$val 4;
$places = (PHP_INT_SIZE 8) - 2;
$res $val << $places;
p($res$val'<<'$places'bits shift out left side');


echo 
"\n--- BIT SHIFT LEFT ON NEGATIVE INTEGERS ---\n";

$val = -4;
$places 1;
$res $val << $places;
p($res$val'<<'$places'zeros fill in right side');

$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'bits shift out left side, including sign bit');


/*
 * このへんは無視してください。
 * たんに結果をきれいに表示させるためだけのものです。
 */

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

    
printf("Expression: %d = %d %s %d\n"$res$val$op$places);

    echo 
" Decimal:\n";
    
printf("  val=%d\n"$val);
    
printf("  res=%d\n"$res);

    echo 
" Binary:\n";
    
printf('  val=' $format$val);
    
printf('  res=' $format$res);

    if (
$note) {
        echo 
" NOTE: $note\n";
    }

    echo 
"\n";
}
?>

上の例の 32 ビットマシンでの出力は、このようになります。


--- BIT SHIFT RIGHT ON POSITIVE INTEGERS ---
Expression: 2 = 4 >> 1
 Decimal:
  val=4
  res=2
 Binary:
  val=00000000000000000000000000000100
  res=00000000000000000000000000000010
 NOTE: copy of sign bit shifted into left side

Expression: 1 = 4 >> 2
 Decimal:
  val=4
  res=1
 Binary:
  val=00000000000000000000000000000100
  res=00000000000000000000000000000001

Expression: 0 = 4 >> 3
 Decimal:
  val=4
  res=0
 Binary:
  val=00000000000000000000000000000100
  res=00000000000000000000000000000000
 NOTE: bits shift out right side

Expression: 0 = 4 >> 4
 Decimal:
  val=4
  res=0
 Binary:
  val=00000000000000000000000000000100
  res=00000000000000000000000000000000
 NOTE: same result as above; can not shift beyond 0


--- BIT SHIFT RIGHT ON NEGATIVE INTEGERS ---
Expression: -2 = -4 >> 1
 Decimal:
  val=-4
  res=-2
 Binary:
  val=11111111111111111111111111111100
  res=11111111111111111111111111111110
 NOTE: copy of sign bit shifted into left side

Expression: -1 = -4 >> 2
 Decimal:
  val=-4
  res=-1
 Binary:
  val=11111111111111111111111111111100
  res=11111111111111111111111111111111
 NOTE: bits shift out right side

Expression: -1 = -4 >> 3
 Decimal:
  val=-4
  res=-1
 Binary:
  val=11111111111111111111111111111100
  res=11111111111111111111111111111111
 NOTE: same result as above; can not shift beyond -1


--- BIT SHIFT LEFT ON POSITIVE INTEGERS ---
Expression: 8 = 4 << 1
 Decimal:
  val=4
  res=8
 Binary:
  val=00000000000000000000000000000100
  res=00000000000000000000000000001000
 NOTE: zeros fill in right side

Expression: 1073741824 = 4 << 28
 Decimal:
  val=4
  res=1073741824
 Binary:
  val=00000000000000000000000000000100
  res=01000000000000000000000000000000

Expression: -2147483648 = 4 << 29
 Decimal:
  val=4
  res=-2147483648
 Binary:
  val=00000000000000000000000000000100
  res=10000000000000000000000000000000
 NOTE: sign bits get shifted out

Expression: 0 = 4 << 30
 Decimal:
  val=4
  res=0
 Binary:
  val=00000000000000000000000000000100
  res=00000000000000000000000000000000
 NOTE: bits shift out left side


--- BIT SHIFT LEFT ON NEGATIVE INTEGERS ---
Expression: -8 = -4 << 1
 Decimal:
  val=-4
  res=-8
 Binary:
  val=11111111111111111111111111111100
  res=11111111111111111111111111111000
 NOTE: zeros fill in right side

Expression: -2147483648 = -4 << 29
 Decimal:
  val=-4
  res=-2147483648
 Binary:
  val=11111111111111111111111111111100
  res=10000000000000000000000000000000

Expression: 0 = -4 << 30
 Decimal:
  val=-4
  res=0
 Binary:
  val=11111111111111111111111111111100
  res=00000000000000000000000000000000
 NOTE: bits shift out left side, including sign bit

上の例の 64 ビットマシンでの出力は、このようになります。


--- BIT SHIFT RIGHT ON POSITIVE INTEGERS ---
Expression: 2 = 4 >> 1
 Decimal:
  val=4
  res=2
 Binary:
  val=0000000000000000000000000000000000000000000000000000000000000100
  res=0000000000000000000000000000000000000000000000000000000000000010
 NOTE: copy of sign bit shifted into left side

Expression: 1 = 4 >> 2
 Decimal:
  val=4
  res=1
 Binary:
  val=0000000000000000000000000000000000000000000000000000000000000100
  res=0000000000000000000000000000000000000000000000000000000000000001

Expression: 0 = 4 >> 3
 Decimal:
  val=4
  res=0
 Binary:
  val=0000000000000000000000000000000000000000000000000000000000000100
  res=0000000000000000000000000000000000000000000000000000000000000000
 NOTE: bits shift out right side

Expression: 0 = 4 >> 4
 Decimal:
  val=4
  res=0
 Binary:
  val=0000000000000000000000000000000000000000000000000000000000000100
  res=0000000000000000000000000000000000000000000000000000000000000000
 NOTE: same result as above; can not shift beyond 0


--- BIT SHIFT RIGHT ON NEGATIVE INTEGERS ---
Expression: -2 = -4 >> 1
 Decimal:
  val=-4
  res=-2
 Binary:
  val=1111111111111111111111111111111111111111111111111111111111111100
  res=1111111111111111111111111111111111111111111111111111111111111110
 NOTE: copy of sign bit shifted into left side

Expression: -1 = -4 >> 2
 Decimal:
  val=-4
  res=-1
 Binary:
  val=1111111111111111111111111111111111111111111111111111111111111100
  res=1111111111111111111111111111111111111111111111111111111111111111
 NOTE: bits shift out right side

Expression: -1 = -4 >> 3
 Decimal:
  val=-4
  res=-1
 Binary:
  val=1111111111111111111111111111111111111111111111111111111111111100
  res=1111111111111111111111111111111111111111111111111111111111111111
 NOTE: same result as above; can not shift beyond -1


--- BIT SHIFT LEFT ON POSITIVE INTEGERS ---
Expression: 8 = 4 << 1
 Decimal:
  val=4
  res=8
 Binary:
  val=0000000000000000000000000000000000000000000000000000000000000100
  res=0000000000000000000000000000000000000000000000000000000000001000
 NOTE: zeros fill in right side

Expression: 4611686018427387904 = 4 << 60
 Decimal:
  val=4
  res=4611686018427387904
 Binary:
  val=0000000000000000000000000000000000000000000000000000000000000100
  res=0100000000000000000000000000000000000000000000000000000000000000

Expression: -9223372036854775808 = 4 << 61
 Decimal:
  val=4
  res=-9223372036854775808
 Binary:
  val=0000000000000000000000000000000000000000000000000000000000000100
  res=1000000000000000000000000000000000000000000000000000000000000000
 NOTE: sign bits get shifted out

Expression: 0 = 4 << 62
 Decimal:
  val=4
  res=0
 Binary:
  val=0000000000000000000000000000000000000000000000000000000000000100
  res=0000000000000000000000000000000000000000000000000000000000000000
 NOTE: bits shift out left side


--- BIT SHIFT LEFT ON NEGATIVE INTEGERS ---
Expression: -8 = -4 << 1
 Decimal:
  val=-4
  res=-8
 Binary:
  val=1111111111111111111111111111111111111111111111111111111111111100
  res=1111111111111111111111111111111111111111111111111111111111111000
 NOTE: zeros fill in right side

Expression: -9223372036854775808 = -4 << 61
 Decimal:
  val=-4
  res=-9223372036854775808
 Binary:
  val=1111111111111111111111111111111111111111111111111111111111111100
  res=1000000000000000000000000000000000000000000000000000000000000000

Expression: 0 = -4 << 62
 Decimal:
  val=-4
  res=0
 Binary:
  val=1111111111111111111111111111111111111111111111111111111111111100
  res=0000000000000000000000000000000000000000000000000000000000000000
 NOTE: bits shift out left side, including sign bit

警告

32 ビットシステムでは 32 ビット以上の右シフトは行わないでください。 また、結果が 32 ビットを超えてしまうような左シフトも行わないでください。 PHP_INT_MAX を超える数のビット演算には、gmp 拡張モジュールの関数を使用します。

pack(), unpack(), gmp_and(), gmp_or(), gmp_xor(), gmp_testbit(), gmp_clrbit() も参照ください。


演算子
PHP Manual