Hola Habr! Les presento la traducción de un artículo de Liam Hammett : Bitmask Constant Arguments en PHP .
PHP contiene muchas funciones estándar que aceptan argumentos booleanos en forma de constantes incorporadas con números binarios.
Estos valores se combinan en un solo argumento de la función para transferir varias banderas booleanas de forma compacta.
Es posible que funcionen un poco diferente de lo que muchas personas imaginan y usan en su código, por lo que sugiero considerar cómo funciona realmente.
Cómo se usa en las funciones de PHP
PHP 7.2, incluidas las extensiones, contiene más de 1800 constantes predefinidas, y algunas de ellas se utilizan como argumentos para las funciones.
Un ejemplo de dicha aplicación es una nueva opción en PHP 7.3, que le permite lanzar una excepción de la función json_encode
para errores de conversión.
json_encode($value, JSON_THROW_ON_ERROR);
Usando |
(o) operador bit a bit, varios argumentos de función funcionan como uno. Un ejemplo de la documentación de PHP:
json_encode($value, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP | JSON_UNESCAPED_UNICODE);
Nada en absoluto
Pero aún así, ¿cómo funciona?
Aplicar operaciones bit a bit para lograr el mismo efecto en el mundo de las funciones definidas por el usuario es realmente simple, pero requiere al menos un conocimiento básico de qué son los bits y cómo funcionan las operaciones bit a bit en PHP.
Los enteros se pueden especificar en sistemas de numeración decimal (base 10), hexadecimal (base 16), octal (base 8) o binario (base 2). [...]
Para escribir en notación binaria, debe poner antes del número 0b.
- php.net
Ejemplos de constantes con un conjunto diferente de números binarios:
const A = 0b0001;
Presta atención al ejemplo y la secuencia de números. Cada valor binario representa un valor dos veces mayor para cada cero al final. Los ceros entre 0b y 1 son opcionales, pero pueden ayudar a alinear el código fuente.
Afortunadamente, necesitamos entender cómo funcionan solo dos operaciones bit a bit.
Bitwise O
No confundir al operador |
( "OR" a nivel de bit ) con el operador de uso frecuente ||
( "OR" lógico ), que generalmente se encuentra en if else
.
El "OR" bit a bit es una operación binaria cuya acción es equivalente a aplicar un "OR" lógico a cada par de bits ubicados en las mismas posiciones en las representaciones binarias de los operandos. En otras palabras, si los dos bits correspondientes de los operandos son 0, el bit binario del resultado es 0; si al menos un bit del par es 1, el bit binario del resultado es 1.
Ejemplo de operación bit a bit "OR":
const A = 0b0001; const B = 0b0010; const C = 0b0100; const D = 0b1000; A | B === 0b0011; A | C | D === 0b1101;
Bitwise AND (AND)
Del mismo modo, el operador &
( bitwise AND ) no debe confundirse con el operador &&
uso frecuente ( AND lógico ).
Un AND bit a bit es una operación binaria cuya acción es equivalente a aplicar un AND lógico a cada par de bits ubicados en las mismas posiciones en las representaciones binarias de los operandos. En otras palabras, si los dos bits correspondientes de los operandos son 1, el bit binario resultante es 1; si al menos un bit del par es 0, el bit binario resultante es 0.
const A = 0b0001; const B = 0b0010; const C = 0b0100; const D = 0b1000; const VALUE = 0b1010; A & B === 0b0000;
¿Puede un número tener un valor booleano?
Vale la pena señalar que en PHP existe el concepto de " manipulación de tipos" ( malabarismo de tipos ). En el lenguaje de los no expertos, esto significa que (PHP) automáticamente intentará convertir datos de un tipo a otro, si es necesario.
Si comprende cómo ocurren tales transformaciones, entonces esta puede ser una herramienta útil.
Por ejemplo, sabemos que el número 0
actúa como false
cuando se convierte a booleano, mientras que todos los demás números serán true
. ¿Recuerdas que estos valores binarios con los que trabajamos son en realidad enteros?
Para resumir!
Ahora podemos combinar este conocimiento para crear una construcción if, cuyo código se ejecutará solo si el resultado de la operación bit a bit entre números no es 0b0000
(o 0
, que se convierte en false
).
const A = 0b0001; const B = 0b0010; function f($arg = 0) { if ($arg & A) { echo 'A'; } if ($arg & B) { echo 'B'; } } f();
Otras funciones PHP integradas (como json_encode
) funcionan de la misma manera.
¿Vale la pena?
Tal vez ahora desee aplicar este enfoque para funciones con una gran cantidad de argumentos que participan en construcciones condicionales, pero hay una serie de desventajas en el procesamiento de indicadores de función bit a bit:
- No puede pasar valores no booleanos a través de un argumento.
- No hay una forma estándar de documentar argumentos usando docblocks.
- Pierde sugerencias generales y soporte para la mayoría de los IDE.
- En cambio, puede pasar una matriz asociativa como argumento para poder establecer valores distintos de cero (o incluso una clase ).
- Hay buenas razones por las que debe evitar el uso de "indicadores de función" lógicos como argumentos y utilizar otra función o método para la funcionalidad mutable.
Sin embargo, ahora sabes cómo hacerlo.
Leer una larga lista de definiciones de constantes puede ser detallado y difícil, así que aquí hay una función auxiliar que simplifica su definición.