Olá Habr! Apresento a você a tradução de um artigo de Liam Hammett : Bitmask Constant Arguments em PHP .
O PHP contém muitas funções padrão que aceitam argumentos booleanos na forma de constantes internas com números binários.
Esses valores são combinados em um único argumento da função para transferir vários sinalizadores booleanos de maneira compacta.
Eles podem funcionar de maneira um pouco diferente do que muitas pessoas imaginam e usam em seus códigos, então sugiro considerar como realmente funciona.
Como é usado nas funções PHP
O PHP 7.2, incluindo extensões, contém mais de 1800 constantes predefinidas e algumas delas são usadas como argumentos para funções.
Um exemplo dessa aplicação é uma nova opção no PHP 7.3, que permite lançar uma exceção da função json_encode
por erros de conversão.
json_encode($value, JSON_THROW_ON_ERROR);
Usando |
(ou) operador bit a bit, vários argumentos de função funcionam como um. Um exemplo da documentação do PHP:
json_encode($value, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP | JSON_UNESCAPED_UNICODE);
Nada mesmo.
Mas ainda assim, como isso funciona?
A aplicação de operações bit a bit para obter o mesmo efeito no mundo das funções definidas pelo usuário é realmente simples, mas requer pelo menos conhecimento básico sobre o que são bits e como as operações bit a bit funcionam no PHP.
Os números inteiros podem ser especificados no sistema de números decimal (base 10), hexadecimal (base 16), octal (base 8) ou binário (base 2). [...]
Para escrever em notação binária, você deve colocar antes do número 0b.
- php.net
Exemplos de constantes com um conjunto diferente de números binários:
const A = 0b0001;
Preste atenção ao exemplo e sequência de números. Cada valor binário representa um valor duas vezes mais alto para cada zero no final. Os zeros entre 0b e 1 são opcionais, mas podem ajudar a alinhar o código-fonte.
Felizmente, precisamos entender como apenas duas operações bit a bit funcionam.
OR bit a bit
Não confunda o operador |
( bit a bit "OR" ) com o operador frequentemente usado ||
( "OR" lógico ), que geralmente é encontrado em if else
.
O "OR" bit a bit é uma operação binária cuja ação é equivalente a aplicar um "OR" lógico a cada par de bits localizado nas mesmas posições nas representações binárias dos operandos. Em outras palavras, se os dois bits correspondentes dos operandos forem 0, o bit binário do resultado será 0; se pelo menos um bit do par for 1, o bit binário do resultado será 1.
Exemplo de operação "OR" bit a bit:
const A = 0b0001; const B = 0b0010; const C = 0b0100; const D = 0b1000; A | B === 0b0011; A | C | D === 0b1101;
AND bit a bit (AND)
Da mesma forma, o operador &
( bit a bit AND ) não deve ser confundido com o operador &&
frequentemente usado ( AND lógico ).
Um AND bit a bit é uma operação binária cuja ação é equivalente a aplicar um AND lógico a cada par de bits localizado nas mesmas posições nas representações binárias dos operandos. Em outras palavras, se os dois bits correspondentes dos operandos forem 1, o bit binário resultante será 1; se pelo menos um bit do par for 0, o bit binário resultante será 0.
const A = 0b0001; const B = 0b0010; const C = 0b0100; const D = 0b1000; const VALUE = 0b1010; A & B === 0b0000;
Um número pode ter um valor booleano?
Vale ressaltar que no PHP existe o conceito de " manipulação de tipos" ( malabarismo de tipos ). Na linguagem de não especialistas, isso significa que ele (PHP) tentará converter automaticamente dados de um tipo para outro, se necessário.
Se você entender como essas transformações ocorrem, isso pode ser uma ferramenta útil.
Por exemplo, sabemos que o número 0
atua como false
ao converter para um booleano, enquanto todos os outros números serão true
. Lembre-se de que esses valores binários com os quais trabalhamos são realmente inteiros?
Para resumir!
Agora podemos combinar esse conhecimento para criar uma construção if, o código no qual será executado apenas se o resultado da operação bit a bit entre números não for 0b0000
(ou 0
, que é convertido em false
).
const A = 0b0001; const B = 0b0010; function f($arg = 0) { if ($arg & A) { echo 'A'; } if ($arg & B) { echo 'B'; } } f();
Outras funções PHP integradas (como json_encode
) funcionam da mesma maneira.
Vale a pena?
Talvez agora você deseje aplicar essa abordagem para funções com um grande número de argumentos que participam de construções condicionais, mas há várias desvantagens no processamento de sinalizadores de função bit a bit:
- Você não pode passar valores não-booleanos através de um argumento.
- Não há uma maneira padrão de documentar argumentos usando docblocks.
- Você perde dicas gerais e suporte para a maioria dos IDEs.
- Em vez disso, você pode passar uma matriz associativa como argumento para poder definir valores diferentes de zero (ou mesmo uma classe ).
- Há boas razões para você evitar o uso de "sinalizadores de função" lógicos como argumentos e usar outra função ou método para funcionalidade mutável.
No entanto, agora você sabe como fazê-lo.
Ler uma longa lista de definições de constantes pode ser detalhada e difícil, então aqui está uma função auxiliar que simplifica sua definição.