битовая манипуляция — Как проверить входные параметры PHP побитовой функции

Иногда в программировании они позволяют связать параметры в одну входную переменную функции, как вторая входная переменная ниже:

define('FLAGA',40);
define('FLAGB',10);
define('FLAGC',3);
function foo($sFile, $vFlags) {
// do something
}
foo('test.txt',FLAGA | FLAGB | FLAGC);

PHP вызывает этот символ одиночной трубы (|) побитовый OR оператор. Как мне теперь что-то добавить внутрь foo() тестировать $vFlags чтобы увидеть, какие флаги были установлены?

3

Решение

Я думаю, вы обнаружите, что флаги, подобные этому, обычно определяются как степени 2, например:

define('FLAGA',1);
define('FLAGB',2);
define('FLAGC',4); /* then 8, 16, 32, etc... */

Как вы правильно сказали, их можно объединить с помощью побитового оператора ИЛИ:

foo('test.txt',FLAGA | FLAGB | FLAGC);

Чтобы проверить эти флаги внутри вашей функции, вам нужно использовать побитовый оператор AND следующим образом:

function foo($sFile, $vFlags) {
if ($vFlags & FLAGA) {
// FLAGA was set
}
if ($vFlags & FLAGB) {
// FLAGB was set
}
//// etc...
}
4

Другие решения

Параметр «flags» будет называться битовая. Один байт содержит 8 битов, которые либо установлены, либо не установлены. Вы просто назначаете свой собственный смысл каждому биту; если установлено, значит да для этого конкретного бита, в противном случае нет.

Поэтому вам нужно начать с определения ваших флагов с правильными значениями, которые устанавливают правильные биты; просто произвольные числа не будут правильно объединены:

define('FLAGA', 1);  // 00000001
define('FLAGB', 2);  // 00000010
define('FLAGC', 4);  // 00000100
define('FLAGD', 8);  // 00001000

Учитывая вышеизложенное, FLAGB | FLAGD создает битовую маску с установленным вторым и четвертым битами (00001010). Для этого вам нужно освоиться с преобразованием между основанием 2 (двоичным) и основанием 10 (десятичным).

Чтобы проверить это, вы используете &:

$flags = FLAGB | FLAGD;

if ($flags & FLAGA) {
echo 'flag A is set';
}

if ($flags & FLAGB) {
echo 'flag B is set';
}

..
2

Вам нужно побитовое AND оператор &:

define('FLAGA',40);
define('FLAGB',10);
define('FLAGC',3);

function foo($sFile, $vFlags) {
if ($vFlags & FLAGA) {
echo "FLAGA is set\n";
}
if ($vFlags & FLAGB) {
echo "FLAGB is set\n";
}
if ($vFlags & FLAGC) {
echo "FLAGC is set\n";
}
}
foo('test.txt',FLAGA | FLAGB | FLAGC);

DEMO

Тем не менее, побитовые операции обязательно работают в двоичном виде, где каждый бит представляет степень 2. Итак, вы, как правило, захотите определить флаги в степени 2, как в

define('FLAGA',1);
define('FLAGB',2);
define('FLAGC',4);
define('FLAGD',8); // etc.

В противном случае, представьте себе этот сценарий:

define('FLAGA',8);
define('FLAGB',32);
define('FLAGC',40);

Если у вас есть значение 40 для $vFlags, вы не можете сказать, какие флаги установлены; это может быть любое из следующего:

FLAGA & FLAGB
FLAGA & FLAGB & FLAGC
FLAGA & FLAGC
FLAGB & FLAGC
FLAGC
0