Opérateurs sur les bits

Les opérateurs sur les bits vous permettent de manipuler les bits dans un entier.

Les opérateurs sur les bits
Exemple Nom Résultat
$a & $b And (Et) Les bits positionnés à 1 dans $a ET dans $b sont positionnés à 1.
$a | $b Or (Ou) Les bits positionnés à 1 dans $a OU $b sont positionnés à 1.
$a ^ $b Xor (ou exclusif) Les bits positionnés à 1 dans $a OU dans $b mais pas dans les deux sont positionnés à 1.
~ $a Not (Non) Les bits qui sont positionnés à 1 dans $a sont positionnés à 0, et vice-versa.
$a << $b Décalage à gauche Décale les bits de $a, $b fois sur la gauche (chaque décalage équivaut à une multiplication par 2).
$a >> $b Décalage à droite Décalage les bits de $a, $b fois par la droite (chaque décalage équivaut à une division par 2).

Le décalage de bits en PHP est arithmétique. Les bits qui sont décalés hors de l'entier sont perdus. Les décalages à gauche font apparaître des zéros à droite, tandis que le bit de signe est décalé à gauche, ce qui signifie que le signe de l'entier n'est pas préservé. Les décalages à droite décalent aussi le bit de signe sur la droite, ce qui signifie que le signe est préservé.

Utilisez des parenthèses pour vous assurer que la précédence voulue est bien appliquée. Par exemple, $a & $b == true applique d'abord l'égalité, et ensuite le ET logique, alors que ($a & $b) == true applique d'abord le ET logique, puis l'égalité.

Prenez garde aux transtypages. Si les deux paramètres, de chaque coté de l'opérateur, sont des chaînes, l'opérateur de bit va opérer sur les valeurs ASCII des chaînes.

      Le rapport d'erreur de PHP utilise des champs de bits,
      qui sont une illustration de l'extinction des bits.
      Pour afficher les erreurs, sauf les notices, les
      instructions du php.ini sont : 
      E_ALL & ~E_NOTICE
     

      Cela se comprend en comparant avec E_ALL :
      00000000000000000111011111111111
      Puis en éteignant la valeur de E_NOTICE...
      00000000000000000000000000001000
      ... et en l'inversant via ~:
      11111111111111111111111111110111
      Finalement, on utilise le ET logique (&) pour lire les bits activés
      dans les deux valeurs : 
      00000000000000000111011111110111
     

      Un autre moyen d'arriver à ce résultat est d'utiliser 
      le OU exclusif (^), qui cherche
      les bits qui ne sont activés que dans l'une ou l'autre des
      valeurs, exclusivement : 
      E_ALL ^ E_NOTICE
     

      error_reporting peut aussi être utilisé pour 
      illustrer l'activation de bits. Pour afficher
      uniquement les erreurs et les erreurs recouvrables,
      on utilise :
      E_ERROR | E_RECOVERABLE_ERROR
     

      Cette approche combine E_ERROR
      00000000000000000000000000000001
      et E_RECOVERABLE_ERROR
      00000000000000000001000000000000
      Avec l'opérateur OR (|) pour s'assurer que
      les bits sont activés dans l'une ou l'autre valeur : 
      00000000000000000001000000000001
     

Exemple #1 Opérations sur les bits et les entiers

<?php
/*
 * Ignorez cette partie,
 * c'est juste du formatage pour clarifier les résultats
 */

$format = '(%1$2d = %1$04b) = (%2$2d = %2$04b)'
		. ' %3$s (%4$2d = %4$04b)' . "\n";

echo <<<EOH
 ---------	 ---------  -- ---------
 resultat	   valeur		test
 ---------	 ---------  -- ---------
EOH;


/*
 * Voici les exemples
 */

$values = array(0, 1, 2, 4, 8);
$test = 1 + 4;

echo "\n Bitwise AND \n";
foreach ($values as $value) {
	$result = $value & $test;
	printf($format, $result, $value, '&', $test);
}

echo "\n Bitwise Inclusive OR \n";
foreach ($values as $value) {
	$result = $value | $test;
	printf($format, $result, $value, '|', $test);
}

echo "\n Bitwise Exclusive OR (XOR) \n";
foreach ($values as $value) {
	$result = $value ^ $test;
	printf($format, $result, $value, '^', $test);
}
?>
<?php
echo 12 ^ 9; // Affiche '5'

echo "12" ^ "9"; // Affiche le caractère d'effacement (ascii 8)
				 // ('1' (ascii 49)) ^ ('9' (ascii 57)) = #8

echo "hallo" ^ "hello"; // Affiche les valeurs ASCII #0 #4 #0 #0 #0
						// 'a' ^ 'e' = #4

echo 2 ^ "3"; // Affiche 1
			  // 2 ^ ((int)"3") == 1

echo "2" ^ 3; // Affiche 1
			  // ((int)"2") ^ 3 == 1
?>

Exemple #3 Décalage de bits sur les entiers

<?php
/*
 * Voici quelques exemples
 */

echo "\n--- Décalages à droite sur des entiers positifs ---\n";

$val = 4;
$places = 1;
$res = $val >> $places;
p($res, $val, '>>', $places, 'copie du bit de signe maintenant à gauche');

$val = 4;
$places = 2;
$res = $val >> $places;
p($res, $val, '>>', $places);

$val = 4;
$places = 3;
$res = $val >> $places;
p($res, $val, '>>', $places, 'des bits sont sortis par la droite');

$val = 4;
$places = 4;
$res = $val >> $places;
p($res, $val, '>>', $places, 'même résultat que ci-dessus : pas de décalage au dela de 0');


echo "\n--- Décalages à droite sur des entiers négatifs ---\n";

$val = -4;
$places = 1;
$res = $val >> $places;
p($res, $val, '>>', $places, 'copie du bit de signe maintenant à gauche');

$val = -4;
$places = 2;
$res = $val >> $places;
p($res, $val, '>>', $places, 'des bits sont sortis par la droite');

$val = -4;
$places = 3;
$res = $val >> $places;
p($res, $val, '>>', $places, 'même résultat que ci-dessus : pas de décalage au dela de -1');


echo "\n--- Décalages à gauche sur des entiers positifs ---\n";

$val = 4;
$places = 1;
$res = $val << $places;
p($res, $val, '<<', $places, 'complément de zéros à droite');

$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, 'le bit de signe est sorti');

$val = 4;
$places = (PHP_INT_SIZE * 8) - 2;
$res = $val << $places;
p($res, $val, '<<', $places, 'des bits sont sortis à gauche');


echo "\n--- Décalages à gauche sur des entiers négatifs ---\n";

$val = -4;
$places = 1;
$res = $val << $places;
p($res, $val, '<<', $places, 'complément de zéros à droite');

$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, 'des bits sont sortis à gauche, y compris le bit de signe');


/*
 * Ignorez cette section
 * Elle contient du code pour le formatage de cet exemple
 */

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 " Décimal :\n";
	printf("  val=%d\n", $val);
	printf("  res=%d\n", $res);

	echo " Binaire :\n";
	printf('  val=' . $format, $val);
	printf('  res=' . $format, $res);

	if ($note) {
		echo " Note : $note\n";
	}

	echo "\n";
}
?>

Résultat de l'exemple ci-dessus sur une machine 32 bits :


--- Décalages à droite sur des entiers positifs ---
Expression : 2 = 4 >> 1
 Décimal :
  val=4
  res=2
 Binaire :
  val=00000000000000000000000000000100
  res=00000000000000000000000000000010
 Note : copie du bit de signe maintenant à gauche

Expression : 1 = 4 >> 2
 Décimal :
  val=4
  res=1
 Binaire :
  val=00000000000000000000000000000100
  res=00000000000000000000000000000001

Expression : 0 = 4 >> 3
 Décimal :
  val=4
  res=0
 Binaire :
  val=00000000000000000000000000000100
  res=00000000000000000000000000000000
 Note : des bits sont sortis par la droite

Expression : 0 = 4 >> 4
 Décimal :
  val=4
  res=0
 Binaire :
  val=00000000000000000000000000000100
  res=00000000000000000000000000000000
 Note : même résultat que ci-dessus : pas de décalage au dela de 0


--- Décalages à droite sur des entiers négatifs ---
Expression : -2 = -4 >> 1
 Décimal :
  val=-4
  res=-2
 Binaire :
  val=11111111111111111111111111111100
  res=11111111111111111111111111111110
 Note : copie du bit de signe à gauche

Expression : -1 = -4 >> 2
 Décimal :
  val=-4
  res=-1
 Binaire :
  val=11111111111111111111111111111100
  res=11111111111111111111111111111111
 Note : des bits sont sortis par la droite

Expression : -1 = -4 >> 3
 Décimal :
  val=-4
  res=-1
 Binaire :
  val=11111111111111111111111111111100
  res=11111111111111111111111111111111
 Note : même résultat que ci-dessus : pas de décalage au dela de -1


--- Décalages à gauche sur des entiers positifs ---
Expression : 8 = 4 << 1
 Décimal :
  val=4
  res=8
 Binaire :
  val=00000000000000000000000000000100
  res=00000000000000000000000000001000
 Note : complément de zéros à droite

Expression : 1073741824 = 4 << 28
 Décimal :
  val=4
  res=1073741824
 Binaire :
  val=00000000000000000000000000000100
  res=01000000000000000000000000000000

Expression : -2147483648 = 4 << 29
 Décimal :
  val=4
  res=-2147483648
 Binaire :
  val=00000000000000000000000000000100
  res=10000000000000000000000000000000
 Note : le bit de signe est sorti

Expression : 0 = 4 << 30
 Décimal :
  val=4
  res=0
 Binaire :
  val=00000000000000000000000000000100
  res=00000000000000000000000000000000
 Note : des bits sont sortis à gauche


--- Décalages à gauche sur des entiers négatifs ---
Expression : -8 = -4 << 1
 Décimal :
  val=-4
  res=-8
 Binaire :
  val=11111111111111111111111111111100
  res=11111111111111111111111111111000
 Note : complément de zéros à droite

Expression : -2147483648 = -4 << 29
 Décimal :
  val=-4
  res=-2147483648
 Binaire :
  val=11111111111111111111111111111100
  res=10000000000000000000000000000000

Expression : 0 = -4 << 30
 Décimal :
  val=-4
  res=0
 Binaire :
  val=11111111111111111111111111111100
  res=00000000000000000000000000000000
 Note : des bits sont sortis à gauche, y compris le bit de signe

Résultat de l'exemple ci-dessus sur une machine 64 bits :


--- Décalages à droite sur des entiers positifs ---
Expression : 2 = 4 >> 1
 Décimal :
  val=4
  res=2
 Binaire :
  val=0000000000000000000000000000000000000000000000000000000000000100
  res=0000000000000000000000000000000000000000000000000000000000000010
 Note : copie du bit de signe maintenant à gauche

Expression : 1 = 4 >> 2
 Décimal :
  val=4
  res=1
 Binaire :
  val=0000000000000000000000000000000000000000000000000000000000000100
  res=0000000000000000000000000000000000000000000000000000000000000001

Expression : 0 = 4 >> 3
 Décimal :
  val=4
  res=0
 Binaire :
  val=0000000000000000000000000000000000000000000000000000000000000100
  res=0000000000000000000000000000000000000000000000000000000000000000
 Note : des bits sont sortis par la droite

Expression : 0 = 4 >> 4
 Décimal :
  val=4
  res=0
 Binaire :
  val=0000000000000000000000000000000000000000000000000000000000000100
  res=0000000000000000000000000000000000000000000000000000000000000000
 Note : même résultat que ci-dessus : pas de décalage au dela de 0


--- Décalages à droite sur des entiers négatifs ---
Expression : -2 = -4 >> 1
 Décimal :
  val=-4
  res=-2
 Binaire :
  val=1111111111111111111111111111111111111111111111111111111111111100
  res=1111111111111111111111111111111111111111111111111111111111111110
 Note : copie du bit de signe maintenant à gauche

Expression : -1 = -4 >> 2
 Décimal :
  val=-4
  res=-1
 Binaire :
  val=1111111111111111111111111111111111111111111111111111111111111100
  res=1111111111111111111111111111111111111111111111111111111111111111
 Note : des bits sont sortis par la droite

Expression : -1 = -4 >> 3
 Décimal :
  val=-4
  res=-1
 Binaire :
  val=1111111111111111111111111111111111111111111111111111111111111100
  res=1111111111111111111111111111111111111111111111111111111111111111
 Note : même résultat que ci-dessus : pas de décalage au dela de -1


--- Décalage à gauche sur les entiers négatifs ---
Expression : 8 = 4 << 1
 Décimal :
  val=4
  res=8
 Binaire :
  val=0000000000000000000000000000000000000000000000000000000000000100
  res=0000000000000000000000000000000000000000000000000000000000001000
 Note : complément de zéros à droite

Expression : 4611686018427387904 = 4 << 60
 Décimal :
  val=4
  res=4611686018427387904
 Binaire :
  val=0000000000000000000000000000000000000000000000000000000000000100
  res=0100000000000000000000000000000000000000000000000000000000000000

Expression : -9223372036854775808 = 4 << 61
 Décimal :
  val=4
  res=-9223372036854775808
 Binaire :
  val=0000000000000000000000000000000000000000000000000000000000000100
  res=1000000000000000000000000000000000000000000000000000000000000000
 Note : le bit de signe est sorti

Expression : 0 = 4 << 62
 Décimal :
  val=4
  res=0
 Binaire :
  val=0000000000000000000000000000000000000000000000000000000000000100
  res=0000000000000000000000000000000000000000000000000000000000000000
 Note : des bits sont sortis à gauche


--- Décalage à gauche sur les entiers négatifs ---
Expression : -8 = -4 << 1
 Décimal :
  val=-4
  res=-8
 Binaire :
  val=1111111111111111111111111111111111111111111111111111111111111100
  res=1111111111111111111111111111111111111111111111111111111111111000
 Note : complément de zéros à droite

Expression : -9223372036854775808 = -4 << 61
 Décimal :
  val=-4
  res=-9223372036854775808
 Binaire :
  val=1111111111111111111111111111111111111111111111111111111111111100
  res=1000000000000000000000000000000000000000000000000000000000000000

Expression : 0 = -4 << 62
 Décimal :
  val=-4
  res=0
 Binaire :
  val=1111111111111111111111111111111111111111111111111111111111111100
  res=0000000000000000000000000000000000000000000000000000000000000000
 Note : des bits sont sortis à gauche, y compris le bit de signe

Avertissement

N'effectuez pas de décalage à droite de plus de 32 bits sur les systèmes 32 bits. N'effectuez pas de décalage à gauche dans le cas où le résultat est un nombre plus long que 32 bits. Utilisez les fonctions de l'extension gmp pour les manipulations sur les bits, lorsque les entiers dépassent PHP_INT_MAX.

Voyez aussi pack(), unpack(), gmp_and(), gmp_or(), gmp_xor(), gmp_testbit(), gmp_clrbit()

LoadingChargement en cours