» » Аргументы функций в виде битовых констант в PHP

 

Аргументы функций в виде битовых констант в PHP

Автор: admin от 14-09-2018, 13:05, посмотрело: 26

Привет, Хабр! Представляю вашему вниманию перевод статьи Лиама Хамметта (Liam Hammett): Bitmask Constant Arguments in PHP.

PHP содержит множество стандартных функций, которые принимают аргументы логического типа (boolean) в форме встроенных констант со значениями двоичных чисел.

Эти значения комбинируются в единый аргумент функции с целью передачи нескольких булевых флагов компактным образом.



Они могут работать немного не так, как многие представляют и используют в своем коде, поэтому предлагаю рассмотреть, как на самом деле это устроено.Пример из PHP документации:



json_encode($value, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP | JSON_UNESCAPED_UNICODE);


Очень даже ничего.



Но все таки, как же это работает?



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



Целые числа могут быть указаны в десятичной (основание 10), шестнадцатеричной (основание 16), восьмеричной (основание 8) или двоичной (основание 2) системе счисления. […] 

Для записи в двоичной системе счисления, необходимо поставить перед числом 0b. 

php.net

Примеры констант с разным набором двоичных чисел:



const A = 0b0001; // 1
const B = 0b0010; // 2
const C = 0b0100; // 4
const D = 0b1000; // 8


Обратите внимание на пример и последовательность чисел. Каждое двоичное значение представляет значение в два раза выше для каждого нуля на конце. Нули между 0b и 1 необязательны, но могут помочь выровнять исходный код.



К счастью, нам необходимо понимать, как работают только две побитовые операции.



Побитовое «ИЛИ» (OR)



Не стоит путать оператор | (побитовое «ИЛИ») с часто используемым оператором || (логическое «ИЛИ»), который обычно встречается в конструкциях if else.

Побитовое «ИЛИ» — это бинарная операция, действие которой эквивалентно применению логического «ИЛИ» к каждой паре битов, находящихся на одинаковых позициях в двоичных представлениях операндов. Другими словами, если оба соответствующих бита операндов равны 0, двоичный разряд результата равен 0; если же хотя бы один бит из пары равен 1, двоичный разряд результата равен 1.



Пример побитовой операции «ИЛИ»:



const A     = 0b0001;
const B     = 0b0010;
const C     = 0b0100;
const D     = 0b1000;
A | B     === 0b0011;
A | C | D === 0b1101;


Побитовое «И» (AND)



Аналогичным образом оператор & (побитовое «И») не стоит путать с часто применяемым оператором && (логическое «И»).

Побитовое «И» — это бинарная операция, действие которой эквивалентно применению логического «И» к каждой паре битов, находящихся на одинаковых позициях в двоичных представлениях операндов. Другими словами, если оба соответствующих бита операндов равны 1, результирующий двоичный разряд равен 1; если же хотя бы один бит из пары равен 0, результирующий двоичный разряд равен 0.



const A     = 0b0001;
const B     = 0b0010;
const C     = 0b0100;
const D     = 0b1000;
const VALUE = 0b1010;
A & B     === 0b0000; // нет совпадений единичных битов в A и B
A & C & D === 0b0000; // нет совпадений единичных битов в A, B или C
A & A     === 0b0001; // тот же бит устанавливается в A дважды
A & VALUE === 0b0000; // нет совпадений единичных битов в A и VALUE
B & VALUE === 0b0010; // бит 1 встречается как в B, так и в VALUE


Может ли число иметь логический тип (boolean)?



Стоит отметить, что в PHP существует понятие «манипуляции с типами» (type juggling). На языке неспециалистов это значит, что он (PHP) автоматически попытается преобразовать данные одного типа к другому, если это потребуется.

Если вы понимаете, как происходят такие преобразования, то это может быть полезным инструментом.

Например, мы знаем, что число 0 выступает в качестве false при преобразовании к логическому типу (boolean), в то время как все остальные числа будут true. Помните, что эти двоичные значения, с которыми мы работаем, на самом деле являются целыми числами?



Подведем итоги!



Теперь мы можем объединить это знание, чтобы создать конструкцию if, код в которой будет выполняться только в том случае, если результат побитовой операции между числами не будет 0b0000 (или 0, который преобразовывается в false).



const A = 0b0001;
const B = 0b0010;

function f($arg = 0)
{
    if ($arg & A) {
        echo 'A';
    }
    if ($arg & B) {
        echo 'B';
    }
}

f();        // nothing
f(A);       // 'A'
f(B);       // 'B'
f(A | B);   // 'AB'


По такому же принципу работают другие встроенные функции PHP (например json_encode).



Стоит ли оно того?



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




  • Вы не можете передавать не булевые значения через аргумент.

  • Нет стандартного способа документировать аргументы с помощью docblocks.

  • Вы теряете общие подсказки и поддержку большинства IDE.

  • Вместо этого вы можете передать ассоциативный массив в качестве аргумента, чтобы иметь возможность устанавливать небулевые значения (или даже класс).

  • Существуют веские причины, по которым вам следует избегать использования логических «флагов функций» в качестве аргументов и вместо этого использовать другую функцию или метод для изменяемой функциональности.



Тем не менее, теперь вы знаете как это делается.





Чтение длинного списка определения констант может быть многословным и трудным, поэтому вот вспомогательная функция упрощающая их определение.



Источник: Хабр / Интересные публикации

Теги: php bitwise

Категория: Программирование

Уважаемый посетитель, Вы зашли на сайт как незарегистрированный пользователь.
Мы рекомендуем Вам зарегистрироваться либо войти на сайт под своим именем.

Добавление комментария

Имя:*
E-Mail:
Комментарий:
Полужирный Наклонный текст Подчеркнутый текст Зачеркнутый текст | Выравнивание по левому краю По центру Выравнивание по правому краю | Вставка смайликов Выбор цвета | Скрытый текст Вставка цитаты Преобразовать выбранный текст из транслитерации в кириллицу Вставка спойлера
Введите два слова, показанных на изображении: *