ビット演算子
ビット演算子は、整数値の特定のビットの評価や操作を行います。
例 | 名前 | 結果 |
---|---|---|
$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 値を使って行います。その結果は文字列になります。
それ以外の場合は、左右のオペランドを integer に変換 し、結果も integer になります。
~ 演算子のオペランドが文字列の場合、その演算は、 文字列を構成する文字の ASCII 値を使って行います。
その結果は文字列になります。
それ以外の場合は、オペランドや演算結果を integer として扱います。
<< および >> 演算子のオペランドとその結果は、常に integer として扱います。
int型はプリミティブ型と呼ばれるタイプで、普段よく使う基本的な整数型変数
Integer型というのは、Objectクラスをスーパークラスとする参照型変数
⇩ ビット演算について詳しくは下記サイトへ。特にビット積、ビット和については見ておいたほうが良いと思われます。PHPマニュアルの説明よく分からんです、自分は。
・[PHP]ビット演算を使ったフラグ処理(2進数のビット操作) | PHP ARCHIVEさんの記事を参考にさせてもらい、ビット演算子のフラグ処理の流れ。
フラグ 【 flag 】
フラグとは、条件判定処理が実行された際に、その結果をデータとして保存しておく領域。
判定処理後に続く命令などが結果を参照して処理に反映させるために用意されている。
メモリやCPU内部のレジスタなどが使われる。CPUのレジスタのうち専らフラグの格納のために用意されたものをフラグレジスタという。
フラグは1ビットで表現され、
・条件が満たされた場合(真)には「true」「1」、
・満たされない場合(偽)には「false」「0」
といった真偽値や数値を取る。
処理の都合上1ビット以上の領域で保存する場合は、
・偽を0に、
・真を「0以外の任意の値」
とする場合が多い。
処理系等によっては真を1あるいは-1などと決めている場合もある。
条件が満たされてフラグが真の値になることを「フラグが立つ」という。
下記のように選択肢がA~Eの5つある場合。
フラグの条件判定
true(はい) = 1
false (いいえ) = 0
A、C、Eがtrueとして有効になります。
<?php
// 定数の設定
class
OptionInfo {
const
NONE = 0b0;
const
OPTION_A = 0b00001;
const
OPTION_B = 0b00010;
const
OPTION_C = 0b00100;
const
OPTION_D = 0b01000;
const
OPTION_E = 0b10000;
}
$option
= OptionInfo::NONE;
// 初期値
// フラグを設定
$option
|= OptionInfo::OPTION_A;
// Aを有効にする
$option
|= OptionInfo::OPTION_C;
// Cを有効にする
$option
|= OptionInfo::OPTION_E;
// Eを有効にする
// 有効になっているフラグを表示
if
(
$option
== OptionInfo::NONE)
echo
'NONE'
;
if
(
$option
& OptionInfo::OPTION_A)
echo
'A'
;
if
(
$option
& OptionInfo::OPTION_B)
echo
'B'
;
if
(
$option
& OptionInfo::OPTION_C)
echo
'C'
;
if
(
$option
& OptionInfo::OPTION_D)
echo
'D'
;
if
(
$option
& OptionInfo::OPTION_E)
echo
'E'
;
別の例では、
・フラグを定義する
フラグに用いる定数は、1, 2, 4, 8, 16, ... など、2の乗数で定義します。
2進数での表記は『0b』を頭につける。
$flag = 1; // 0b0000 #フラグの初期値
$A_FLAG = 1; // 0b0001(2の0乗の値が1なので1) # Aフラグの定義
$B_FLAG = 2; // 0b0010(2の1乗の値が1なので2) # Bフラグの定義
$C_FLAG = 4; // 0b0100(2の2乗の値が1なので4) # Cフラグの定義
$D_FLAG = 8; // 0b1000(2の3乗の値が1なので8) # Dフラグの定義
・フラグを立てる・降ろす
フラグを立てるには |= 演算子、フラグを降ろすには &= と ~ 演算子
$flag |= $B_FLAG; # フラグを立てる
// ⇧ $flag = $flag | $B_FLAGなので、『0b0001』と『0b0010』のビット和なので『0b0011』。『0b0011』がフラグとなります。
$flag &= ~$B_FLAG; # フラグを降ろす
・フラグをチェックする
チェックするには & 演算子
(※ $flag |= $B_FLAG; の状態になってるものとしてチェックしてます。)
if ($flag & $A_FLAG) { ... } # フラグが立っているかチェックする
// ⇧ 『0b0011』と『0b0001』のビット積で、結果は『0b0001』、つまり『1』となるので、フラグの『0b0011』と比較し、『1』は論理値『TRUE』として変換されるので『... 』の処理が実行されます。
if ($flag & $B_FLAG) { ... } # フラグが立っているかチェックする
// ⇧ 『0b0011』と『0b0010』のビット積で、結果は『0b0010』、つまり『2』となるので、フラグの『0b0011』と比較し、『2』は論理値『TRUE』として変換されるので『... 』の処理が実行されます。
if ($flag & $C_FLAG) { ... } # フラグが立っているかチェックする
// ⇧ 『0b0011』と『0b0100』のビット積で、結果は『0b0000』、つまり『0』となるので、フラグの『0b0011』と比較し、『0』は論理値『FALSE』として変換されるので『... 』の処理は実行されません。
if ($flag & $D_FLAG) { ... } # フラグが立っているかチェックする
// ⇧ 『0b0011』と『0b1000』のビット積で、結果は『0b0000』、つまり『0』となるので、フラグの『0b0011』と比較し、『0』は論理値『FALSE』として変換されるので『... 』の処理は実行されません。
ビット演算と代入を同時にできる演算子
$a = $a & $b なら $a &= $b
$a = $a | $b なら $a |= $b
$a = $a ^ $b なら $a ^= $b
$a = $a << $b なら $a <<= $b
$a = $a >> $b なら $a >>= $b
これらを参考に自分のぶつかった問題を解析すると、
よく理解できてないのですが、
『$ans |= (1 << $qno);』は、$ans = $ans | (1 << $qno)となるので、
まず、左シフトで『1(0b0001)』を左に『$qno』分シフトし、その結果の値と$ansのビット和をフラグの値としてる、ということらしいです。
$qno = 0(0b0000)の場合 ⇒ $ans = 1(0b0001)
$qno = 1(0b0001)の場合 ⇒ $ans = 2(0b0010)
$qno = 2(0b0010)の場合 ⇒ $ans = 4(0b0100)
$qno = 3(0b0011)の場合 ⇒ $ans = 8(0b1000)
これで、ユーザーがいま何番目の質問に答えているのか判定してるようです。
『プロになるための PHPプログラミング入門 (著)星野 香保子 』という書籍の中の「第1章 PHPでWeb開発をしてみませんか」の「1.6 セッション管理をするには」で出てきました。
ここでは一部しかコードを載せてないので、一連の流れを知りたい方は書籍で調べてみてください。