Los operadores bit a bit permiten la evaluación y la manipulación de bits específicos dentro de un integer.
Ejemplo | Nombre | Resultado |
---|---|---|
$a & $b |
And (y) | Los bits que están activos en ambos $a y $b son activados. |
$a | $b |
Or (o inclusivo) | Los bits que están activos ya sea en $a o en $b son activados. |
$a ^ $b |
Xor (o exclusivo) | Los bits que están activos en $a o en $b, pero no en ambos, son activados. |
~ $a |
Not (no) | Los bits que están activos en $a son desactivados, y viceversa. |
$a << $b |
Shift left(desplazamiento a izquierda) | Desplaza los bits de $a, $b pasos a la izquierda (cada paso quiere decir "multiplicar por dos"). |
$a >> $b |
Shift right (desplazamiento a derecha) | Desplaza los bits de $a, $b pasos a la derecha (cada paso quiere decir "dividir por dos"). |
El desplazamiento de bits en PHP es aritmético. Los bits desplazados por fuera de cualquiera de los extremos son descartados. Desplazamientos de izquierda tienen ceros desplazados a la derecha mientras que el bit de signo es desplazado fuera a la izquierda, es decir que no se conserva el signo de un operando. Desplazamientos a la derecha tienen copias del bit de signo desplazado a la izquierda, es decir que se conserva el signo de un operando.
Utilice paréntesis para garantizar la precedencia deseada. Por ejemplo, $a & $b == true evalúa la equivalencia y luego el bit a bit, mientras que ($a & $b) == true evalúa el bit a bit y luego la equivalencia.
Sea consciente de las conversiones de tipos de datos. Si tanto los parámetros de la izquierda como los de la derecha son cadenas, el operador bit a bit operará en los valores ASCII de los caracteres.
La configuración error_reporting del PHP ini utiliza valores de bit a bit,
lo que ofrece una demostración del mundo real de desactivar
bits. Para mostrar todos los errores, a excepción de los avisos,
las instrucciones del archivo php.ini dicen utilizar:
E_ALL & ~E_NOTICE
Esto funciona iniciando con E_ALL: 00000000000000000111011111111111 Luego se toma el valor de E_NOTICE ... 00000000000000000000000000001000 ... y se invierte por medio de ~: 11111111111111111111111111110111 Finalmente, se utiliza AND (&) para encontrar los bits que se activaron en ambos valores: 00000000000000000111011111110111
Otra forma de lograrlo es mediante XOR (^)
para encontrar los bits que están activados en sólo el primer valor o en el otro:
E_ALL ^ E_NOTICE
error_reporting también se puede utilizar para demostrar la activación de bits.
La forma para mostrar sólo los errores y los errores recuperables es:
E_ERROR | E_RECOVERABLE_ERROR
Este proceso combina E_ERROR 00000000000000000000000000000001 y 00000000000000000001000000000000 usando el operador OR (|) para obtener los bits activados en cualquiera de estos valores: 00000000000000000001000000000001
Ejemplo #1 Operaciones AND, OR y XOR bit a bit sobre integers
<?php
/*
* Ignore la sección superior,
* es sólo el formateado para hacer la salida más clara.
*/
$format = '(%1$2d = %1$04b) = (%2$2d = %2$04b)'
. ' %3$s (%4$2d = %4$04b)' . "\n";
echo <<<EOH
--------- --------- -- ---------
resultado valor op prueba
--------- --------- -- ---------
EOH;
/*
* Aquí están los ejemplos.
*/
$values = array(0, 1, 2, 4, 8);
$test = 1 + 4;
echo "\n AND bit a bit \n";
foreach ($values as $value) {
$result = $value & $test;
printf($format, $result, $value, '&', $test);
}
echo "\n OR inclusivo bit a bit \n";
foreach ($values as $value) {
$result = $value | $test;
printf($format, $result, $value, '|', $test);
}
echo "\n OR exclusivo (XOR) bit a bit \n";
foreach ($values as $value) {
$result = $value ^ $test;
printf($format, $result, $value, '^', $test);
}
?>
El resultado del ejemplo sería:
--------- --------- -- --------- resultado valor op prueba --------- --------- -- --------- AND bit a bit ( 0 = 0000) = ( 0 = 0000) & ( 5 = 0101) ( 1 = 0001) = ( 1 = 0001) & ( 5 = 0101) ( 0 = 0000) = ( 2 = 0010) & ( 5 = 0101) ( 4 = 0100) = ( 4 = 0100) & ( 5 = 0101) ( 0 = 0000) = ( 8 = 1000) & ( 5 = 0101) OR inclusivo bit a bit ( 5 = 0101) = ( 0 = 0000) | ( 5 = 0101) ( 5 = 0101) = ( 1 = 0001) | ( 5 = 0101) ( 7 = 0111) = ( 2 = 0010) | ( 5 = 0101) ( 5 = 0101) = ( 4 = 0100) | ( 5 = 0101) (13 = 1101) = ( 8 = 1000) | ( 5 = 0101) OR exclusivo (XOR) bit a bit ( 5 = 0101) = ( 0 = 0000) ^ ( 5 = 0101) ( 4 = 0100) = ( 1 = 0001) ^ ( 5 = 0101) ( 7 = 0111) = ( 2 = 0010) ^ ( 5 = 0101) ( 1 = 0001) = ( 4 = 0100) ^ ( 5 = 0101) (13 = 1101) = ( 8 = 1000) ^ ( 5 = 0101)
Ejemplo #2 Operaciones XOR bit a bit sobre strings
<?php
echo 12 ^ 9; // Sale '5'
echo "12" ^ "9"; // Sale el caracter de retroceso (ascii 8)
// ('1' (ascii 49)) ^ ('9' (ascii 57)) = #8
echo "hallo" ^ "hello"; // Salen los valores ascii #0 #4 #0 #0 #0
// 'a' ^ 'e' = #4
echo 2 ^ "3"; // Sale 1
// 2 ^ ((int)"3") == 1
echo "2" ^ 3; // Sale 1
// ((int)"2") ^ 3 == 1
?>
Ejemplo #3 Desplazamiento de bits sobre integers
<?php
/*
* Aquí están los ejemplos.
*/
echo "\n--- DESPLAZAMIENTO DE BITS A LA DERECHA SOBRE ENTEROS POSITIVOS ---\n";
$val = 4;
$places = 1;
$res = $val >> $places;
p($res, $val, '>>', $places, 'copia del bit de signo desplazado hacia el lado izquierdo');
$val = 4;
$places = 2;
$res = $val >> $places;
p($res, $val, '>>', $places);
$val = 4;
$places = 3;
$res = $val >> $places;
p($res, $val, '>>', $places, 'bits desplazados fuera del lado derecho');
$val = 4;
$places = 4;
$res = $val >> $places;
p($res, $val, '>>', $places, 'mismo resultado que arriba; no se puede desplazar más allá del 0');
echo "\n--- DESPLAZAMIENTO DE BITS A LA DERECHA SOBRE ENTEROS NEGATIVOS ---\n";
$val = -4;
$places = 1;
$res = $val >> $places;
p($res, $val, '>>', $places, 'copia del bit de signo desplazado al lado izquierdo');
$val = -4;
$places = 2;
$res = $val >> $places;
p($res, $val, '>>', $places, 'bits desplazados fuera del lado derecho');
$val = -4;
$places = 3;
$res = $val >> $places;
p($res, $val, '>>', $places, 'mismo resultado que arriba; no se puede desplazar más allá del -1');
echo "\n--- DESPLAZAMIENTO DE BITS A LA IZQUIERDA SOBRE ENTEROS POSITIVOS ---\n";
$val = 4;
$places = 1;
$res = $val << $places;
p($res, $val, '<<', $places, 'ceros rellenan en el lado derecho');
$val = 4;
$places = (PHP_INT_SIZE * 8) - 4;
$res = $val << $places;
p($res, $val, '<<', $places);
$val = 4;
$places = (PHP_INT_SIZE * 8) - 3;
$res = $val << $places;
p($res, $val, '<<', $places, 'bit de signo resulta desplazado fuera');
$val = 4;
$places = (PHP_INT_SIZE * 8) - 2;
$res = $val << $places;
p($res, $val, '<<', $places, 'bit de signo desplazado fuera del lado izquierdo');
echo "\n--- DESPLAZAMIENTO DE BITS A LA IZQUIERDA SOBRE ENTEROS NEGATIVOS ---\n";
$val = -4;
$places = 1;
$res = $val << $places;
p($res, $val, '<<', $places, 'ceros rellenan en el lado derecho');
$val = -4;
$places = (PHP_INT_SIZE * 8) - 3;
$res = $val << $places;
p($res, $val, '<<', $places);
$val = -4;
$places = (PHP_INT_SIZE * 8) - 2;
$res = $val << $places;
p($res, $val, '<<', $places, 'bits desplazados fuera del lado izquierdo, incluyendo el bit de signo');
/*
* Ignore this bottom section,
* it is just formatting to make output clearer.
*/
function p($res, $val, $op, $places, $note = '') {
$format = '%0' . (PHP_INT_SIZE * 8) . "b\n";
printf("Expression: %d = %d %s %d\n", $res, $val, $op, $places);
echo " Decimal:\n";
printf(" val=%d\n", $val);
printf(" res=%d\n", $res);
echo " Binary:\n";
printf(' val=' . $format, $val);
printf(' res=' . $format, $res);
if ($note) {
echo " NOTE: $note\n";
}
echo "\n";
}
?>
El resultado del ejemplo en equipos de 32 bits sería:
--- DESPLAZAMIENTO DE BITS A LA DERECHA SOBRE ENTEROS POSITIVOS --- Expression: 2 = 4 >> 1 Decimal: val=4 res=2 Binary: val=00000000000000000000000000000100 res=00000000000000000000000000000010 NOTE: copia del bit de signo desplazado hacia el lado izquierdo Expression: 1 = 4 >> 2 Decimal: val=4 res=1 Binary: val=00000000000000000000000000000100 res=00000000000000000000000000000001 Expression: 0 = 4 >> 3 Decimal: val=4 res=0 Binary: val=00000000000000000000000000000100 res=00000000000000000000000000000000 NOTE: bits desplazados fuera del lado derecho Expression: 0 = 4 >> 4 Decimal: val=4 res=0 Binary: val=00000000000000000000000000000100 res=00000000000000000000000000000000 NOTE: mismo resultado que arriba; no se puede desplazar más allá del 0 --- DESPLAZAMIENTO DE BITS A LA DERECHA SOBRE ENTEROS NEGATIVOS --- Expression: -2 = -4 >> 1 Decimal: val=-4 res=-2 Binary: val=11111111111111111111111111111100 res=11111111111111111111111111111110 NOTE: copia del bit de signo desplazado al lado izquierdo Expression: -1 = -4 >> 2 Decimal: val=-4 res=-1 Binary: val=11111111111111111111111111111100 res=11111111111111111111111111111111 NOTE: bits desplazados fuera del lado derecho Expression: -1 = -4 >> 3 Decimal: val=-4 res=-1 Binary: val=11111111111111111111111111111100 res=11111111111111111111111111111111 NOTE: mismo resultado que arriba; no se puede desplazar más allá del -1 --- DESPLAZAMIENTO DE BITS A LA IZQUIERDA SOBRE ENTEROS POSITIVOS --- Expression: 8 = 4 << 1 Decimal: val=4 res=8 Binary: val=00000000000000000000000000000100 res=00000000000000000000000000001000 NOTE: ceros rellenan en el lado derecho Expression: 1073741824 = 4 << 28 Decimal: val=4 res=1073741824 Binary: val=00000000000000000000000000000100 res=01000000000000000000000000000000 Expression: -2147483648 = 4 << 29 Decimal: val=4 res=-2147483648 Binary: val=00000000000000000000000000000100 res=10000000000000000000000000000000 NOTE: bit de signo resulta desplazado fuera Expression: 0 = 4 << 30 Decimal: val=4 res=0 Binary: val=00000000000000000000000000000100 res=00000000000000000000000000000000 NOTE: bit de signo desplazado fuera del lado izquierdo --- DESPLAZAMIENTO DE BITS A LA IZQUIERDA SOBRE ENTEROS NEGATIVOS --- Expression: -8 = -4 << 1 Decimal: val=-4 res=-8 Binary: val=11111111111111111111111111111100 res=11111111111111111111111111111000 NOTE: ceros rellenan en el lado derecho Expression: -2147483648 = -4 << 29 Decimal: val=-4 res=-2147483648 Binary: val=11111111111111111111111111111100 res=10000000000000000000000000000000 Expression: 0 = -4 << 30 Decimal: val=-4 res=0 Binary: val=11111111111111111111111111111100 res=00000000000000000000000000000000 NOTE: bits desplazados fuera del lado izquierdo, incluyendo el bit de signo
El resultado del ejemplo en equipos de 64 bits sería:
--- DESPLAZAMIENTO DE BITS A LA DERECHA SOBRE ENTEROS POSITIVOS --- Expression: 2 = 4 >> 1 Decimal: val=4 res=2 Binary: val=0000000000000000000000000000000000000000000000000000000000000100 res=0000000000000000000000000000000000000000000000000000000000000010 NOTE: copia del bit de signo desplazado hacia el lado izquierdo Expression: 1 = 4 >> 2 Decimal: val=4 res=1 Binary: val=0000000000000000000000000000000000000000000000000000000000000100 res=0000000000000000000000000000000000000000000000000000000000000001 Expression: 0 = 4 >> 3 Decimal: val=4 res=0 Binary: val=0000000000000000000000000000000000000000000000000000000000000100 res=0000000000000000000000000000000000000000000000000000000000000000 NOTE: bits desplazados fuera del lado derecho Expression: 0 = 4 >> 4 Decimal: val=4 res=0 Binary: val=0000000000000000000000000000000000000000000000000000000000000100 res=0000000000000000000000000000000000000000000000000000000000000000 NOTE: mismo resultado que arriba; no se puede desplazar más allá del 0 --- DESPLAZAMIENTO DE BITS A LA DERECHA SOBRE ENTEROS NEGATIVOS --- Expression: -2 = -4 >> 1 Decimal: val=-4 res=-2 Binary: val=1111111111111111111111111111111111111111111111111111111111111100 res=1111111111111111111111111111111111111111111111111111111111111110 NOTE: copia del bit de signo desplazado al lado izquierdo Expression: -1 = -4 >> 2 Decimal: val=-4 res=-1 Binary: val=1111111111111111111111111111111111111111111111111111111111111100 res=1111111111111111111111111111111111111111111111111111111111111111 NOTE: bits desplazados fuera del lado derecho Expression: -1 = -4 >> 3 Decimal: val=-4 res=-1 Binary: val=1111111111111111111111111111111111111111111111111111111111111100 res=1111111111111111111111111111111111111111111111111111111111111111 NOTE: mismo resultado que arriba; no se puede desplazar más allá del -1 --- DESPLAZAMIENTO DE BITS A LA IZQUIERDA SOBRE ENTEROS POSITIVOS --- Expression: 8 = 4 << 1 Decimal: val=4 res=8 Binary: val=0000000000000000000000000000000000000000000000000000000000000100 res=0000000000000000000000000000000000000000000000000000000000001000 NOTE: ceros rellenan en el lado derecho Expression: 4611686018427387904 = 4 << 60 Decimal: val=4 res=4611686018427387904 Binary: val=0000000000000000000000000000000000000000000000000000000000000100 res=0100000000000000000000000000000000000000000000000000000000000000 Expression: -9223372036854775808 = 4 << 61 Decimal: val=4 res=-9223372036854775808 Binary: val=0000000000000000000000000000000000000000000000000000000000000100 res=1000000000000000000000000000000000000000000000000000000000000000 NOTE: bit de signo resulta desplazado fuera Expression: 0 = 4 << 62 Decimal: val=4 res=0 Binary: val=0000000000000000000000000000000000000000000000000000000000000100 res=0000000000000000000000000000000000000000000000000000000000000000 NOTE: bit de signo desplazado fuera del lado izquierdo --- DESPLAZAMIENTO DE BITS A LA IZQUIERDA SOBRE ENTEROS NEGATIVOS --- Expression: -8 = -4 << 1 Decimal: val=-4 res=-8 Binary: val=1111111111111111111111111111111111111111111111111111111111111100 res=1111111111111111111111111111111111111111111111111111111111111000 NOTE: ceros rellenan en el lado derecho Expression: -9223372036854775808 = -4 << 61 Decimal: val=-4 res=-9223372036854775808 Binary: val=1111111111111111111111111111111111111111111111111111111111111100 res=1000000000000000000000000000000000000000000000000000000000000000 Expression: 0 = -4 << 62 Decimal: val=-4 res=0 Binary: val=1111111111111111111111111111111111111111111111111111111111111100 res=0000000000000000000000000000000000000000000000000000000000000000 NOTE: bits desplazados fuera del lado izquierdo, incluyendo el bit de signo
No desplazar a la derecha más de 32 bits en sistemas de 32 bits. No desplazar a la izquierda en caso de que resulte en un número más largo de 32 bits. Usar funciones de la extensión gmp para manipulación bit a bit sobre números más allá de PHP_INT_MAX.
Ver también pack(), unpack(), gmp_and(), gmp_or(), gmp_xor(), gmp_testbit(), gmp_clrbit()