Обложка канала

Beer::PHP 🍺

3025 @beerphp

Здесь публикуются короткие заметки о PHP, Linux, Unit Testing, DB, OOP, etc., выдержки из статей, книг, видео, курсов и других материалов. Теперь тебе больше не нужно перерывать тонны информации ;)

Beer::PHP 🍺

5 лет назад
Открыть в
Битовые операции (часть 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