Битовые операции в PHP на примерах
Навеяно статьей об обработке критических ошибок в PHP. Обратил внимание, что несмотря на то, что коды ошибок в PHP специально заточены под битовые операции, тем не менее, что в примерах статьи, что в комментариях, для проверки кодов ошибок используются обычные операторы сравнения.
Например, встречались такие варианты:
if ( $error['type'] == E_ERROR || $error['type'] == E_PARSE || $error['type'] == E_COMPILE_ERROR ) {...}
Или:
if ( in_array( $error['type'], array( E_ERROR, E_PARSE, E_COMPILE_ERROR ) ) {...}
В связи с этим решил написать небольшую статью о битовых операциях с примерами их использования.
Немного теории
Число в двоичной (бинарной) системе исчисления представляет собой набор нулей и единиц. Самый правый бит, нулевой, называется младшим значащим битом (разрядом).
Например, число 5
будет выглядеть, как 00000101
.
Всего в наличии 6 побитовых операторов:
$a & $b
— И (получаем число в котором установлены биты, которые установлены в $a и в $b)$a | $b
— Или (получаем число в котором установлены биты, которые установлены в $a или в $b)$a ^ $b
— Исключающее или (число в котором установлены биты установленные в $a или в $b, но не в обоих одновременно)~$a
— Отрицание (инверсия, 1 меняется на 0, и наоборот)$a < < $b
— Сдвиг влево (все биты в $a смещаются влево на количество позиций в $b)$a >> $b
— Сдвиг вправо (все биты в $a смещаются вправо на количество позиций в $b)
Практика на примерах
Для большей наглядности рассмотрим в качестве примера, простую систему разграничения прав доступа к сайту.
У нас будут доступны следующие права доступа: Чтение, Создание, Редактирование, Удаление. То есть всего 4 значения, их можно представить в виде 4-х битного числа, в котором 1 — означает, что у пользователя есть данное право, а 0 — нет.
Для наглядности нарисовал картинку.
Определим для прав доступа следующие константы:
define( 'U_READ', 1 << 0 ); // 0001
define( 'U_CREATE', 1 << 1 ); // 0010
define( 'U_EDIT', 1 << 2 ); // 0100
define( 'U_DELETE', 1 << 3 ); // 1000
define( 'U_ALL', U_READ | U_CREATE | U_EDIT | U_DELETE ); // 1111
Установка значений битов
Присваиваем одно право.
$user_perm = U_READ; // только право чтения
Чтобы комбинировать несколько прав используем побитовый оператор ИЛИ.
$user_perm = U_READ | U_DELETE; // можно читать и удалять
Добавляем все права с помощью заготовленной константы.
$user_perm = U_ALL; // все права
Если нужно дать все права кроме одного или нескольких, то можно воспользоваться следующими операторами.
$user_perm = U_ALL ^ U_DELETE; // все права кроме удаления
$user_perm = U_ALL & ~ U_DELETE; // все права кроме удаления, в данном случае 2 оператора
Разница между этими вариантами в том, что в первом случае просто переключается бит, если был 1, то станет 0, и наоборот.
Второй же вариант делает бит равным 0, независимо от его текущего значения.
Проверка значения бита
Выставлять биты мы уже научились, теперь рассмотрим как же их использовать, т.е. проверять значение. Для проверки наличия прав доступа используем побитовый оператор И
.
if ( $user_perm & U_READ ) // есть ли право чтения?
Можно проверять значения сразу нескольких бит, к примеру:
if ( $user_perm & ( U_READ | U_DELETE ) ) // есть ли право чтения и/или удаления
Сброс бита
Если мы хотим убрать какое-нибудь право доступа, то пишем так:
$user_perm &= ~ U_DELETE; // запретить удаление
Послесловие
Если вернуться к проверке ошибок. То примеры из начала статьи, можно заменить на:
if( $error['type'] & ( E_ERROR | E_PARSE | E_COMPILE_ERROR ) ) {...}
Ссылки
Опубликовано с позволения автора (zapimir). Оригинал находится на Хабре.
а бы почему сброс бита не вот так сделать?
$user_perm ^= U_DELETE;
С этим вопросом ван надо к zapimir обратиться — он автор статьи