2021-09-17 09:00:12
Битовые операции (часть 2)
В прошлой части мы рассмотрели побитовые сдвиги влево и вправо, сегодня рассмотрим остальные 4 операции — AND & , OR | , XOR ^, NOT ~.
Для примера рассмотрим простую систему разграничения прав доступа к сайту.
У нас будут доступны следующие права доступа: Чтение, Создание, Редактирование, Удаление. То есть всего 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
В первых 4 строках мы задали константы с помощью сдвига влево. А в пятой строке использовали оператор OR |. Он выполняет операцию над каждым битом своих операндов. Бит результата устанавливается, если соответствующий бит установлен хотя бы в одном операнде. Например:
$x = 3; // 0011
$y = 5; // 0101
echo $x | $y; // 0111 (7)
Таким образом мы можем задать любые разрешения для пользователя:
$userPermission = U_READ; // только право чтения
$userPermission = U_READ | U_CREATE; // можно читать и создавать
$userPermission = U_ALL ^ U_DELETE; // все права кроме удаления
$userPermission = U_ALL & ~ U_DELETE; // тоже все права кроме удаления
В данном примере мы видим XOR ^ (исключающее или). Бит устанавливается, если соответствующий бит установлен в одном (но не в обоих) из двух операндов.
$x = 3; // 0011
$y = 5; // 0101
echo $x ^ $y; // 0110 (6)
В нашем случае:
U_ALL 1111
U_DELETE 1000
RESULT 0111
В следующей строке сразу 2 оператора AND & и NOT ~. Оператор & выполняет операцию логическое И над каждым битом своих операндов. Бит результата устанавливается, если соответствующий бит установлен в обоих операндах:
$x = 3; // 0011
$y = 5; // 0101
echo $x & $y; // 0001 (1)
Оператор NOT ~ представляет собой унарный оператор, указываемый перед своим единственным операндом. Он выполняет инверсию всех битов операнда. Из-за способа представления целых со знаком в PHP применение оператора ~ к значению эквивалентно изменению его знака и вычитанию 1.
$y = 5; // 0101
echo ~$y; // 1010 (-6)
Таким образом в нашем примере сначала сработает оператор NOT. U_DELETE из 1000 станет 0111, а затем вызовется оператор &
U_ALL 1111
~ U_DELETE 0111
RESULT 0111
Разница между этими вариантами в том, что в первом случае просто переключается бит, если был 1, то станет 0, и наоборот. Второй же вариант делает бит равным 0, независимо от его текущего значения.
Если мы хотим убрать какое-нибудь право доступа, то пишем так:
$userPermission &= ~ U_DELETE; // запретить удаление
Для проверки битов (в нашем случае прав доступа) можно использовать следующие конструкции.
if ($userPermission & U_READ) // есть ли право чтения?
if ($userPermission & (U_READ | U_DELETE)) // есть ли право чтения и/или удаления
Еще один пример:
// Вместо
if ($error['type'] == E_ERROR || $error['type'] == E_PARSE || $error['type'] == E_COMPILE_ERROR) {}
// Или
if (in_array($error['type'], [E_ERROR, E_PARSE, E_COMPILE_ERROR])) {}
// Можно использовать
if ($error['type'] & (E_ERROR | E_PARSE | E_COMPILE_ERROR)) {}
Несмотря на то, что коды ошибок в PHP специально заточены под битовые операции, тем не менее, достаточно часто для проверки кодов ошибок используются обычные операторы сравнения. Но теперь вы знаете, что можно сравнивать и побитово ;)
#php #junior #source
1.4K viewsКирилл Сулимовский, edited 06:00