## Operadores bit a bit

Los operadores bit a bit permiten la evaluación y la manipulación de bits específicos dentro de un integer.

Operadores bit a bit
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.

Si los operandos para los operadores `&`, `|` y `^` son string, la operación se realizará con los valores ASCII de los caracteres que componen dichos string, y el resultado será también un string. En todos los demás casos, ambos operandos serán convertidos a valores de tipo integer y el resultado será también un integer.

Si el operando del operados `~` es un string, la operación se realizará con valores los ASCII de los caracteres que componen dicho string, y el resultado también será un string; en caso contrario, el operando y el resultado serán tratados como valores de tipo integer.

Ambos operandos y el resultado de lo operadores `<<` y `>>` siempre son tratados como valores de tipo integer.

          El ajuste ini error_reporting utiliza valores a nivel de 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 bit 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 bit 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

Advertencia

Desplazar un integer por valores mayores o iguales al ancho del tipo long integer del sistema resultará en un comportamiento indefinido. En otras palabras, no desplace más de 31 bit en sistemas de 32 bit, y no desplace más de 63 bit en sistemas de 64 bit.

Use funciones de la extensión gmp para manipular a nivel de bit números mayores que `PHP_INT_MAX`.

Ver también pack(), unpack(), gmp_and(), gmp_or(), gmp_xor(), gmp_testbit(), gmp_clrbit()