Les opérateurs bitwise

Mars 2013

Les opérateurs sur les bits (appelé bitwise operators en anglais) sont en général assez méconnu des développeurs PHP, et pourtant ils peuvent s'avérer très utiles.

On peut notamment les utiliser pour spécifier des options à une fonction, à la place d'un array. Imaginons que vous ayez une fonction un peu complexe dont il est possible de personnaliser le fonctionnement avec une série d'options facultatives :

Utiliser une fonction avec beaucoup d'arguments ça n'est pas pratique du tout, ça oblige à remplir des arguments inutilement à cause de l'ordre des paramètres dans le prototype de la fonction :

usine_a_gaz($option1, $option2, null, null, null, null, $option7);

Utiliser un array (tableau) rend l'utilisation de la fonction déjà beaucoup plus facile, on peut spécifier uniquement les paramètres dont on a besoin. Sauf que la syntaxe est un peu lourde, et ça n'est pas une approche très "propre".

usine_a_gaz(
	array(
		'option1' => $option1,
		'option2' => $option2,
		'option7' => $option7
	)
);

La solution la plus propre consiste à utiliser les opérateurs sur les bit (souvent appelés avec des constantes) :

usine_a_gaz(UAG_OPTION1 | UAG_OPTION2 | UAG_OPTION7);

Comment ça marche ?

En fait, le principe est d'attribuer un entier à chaque option gérée par votre fonction. Et pas n'importe quel entier (32 bit), seulement des puissances de 2 : 1, 2, 4, 8, 16, 32, 64 ... jusque 2147483648 (2^31 et pas 2^32, car PHP ne supporte pas les entiers non signés).

Par exemple :

define('UAG_OPTION1', 1);
define('UAG_OPTION2', 2);
define('UAG_OPTION3', 4);

Maintenant si on regarde à quoi ressemblent ces 3 entiers (1, 2 et 4) en binaire, voilà ce qu'on voit :

Decimal   Binaire
      1       001
      2       010
      4       100

Comme par hasard, les puissances de 2 ont la particularité de commencer par un 1, suivi uniquement de 0, avec le 1 qui se décale à gauche pour chaque puissance. Du coup on peut créer toutes les combinaisons d'options possibles :

Aucune option                           : 000
UAG_OPTION1                             : 001
UAG_OPTION1 | UAG_OPTION2               : 010
UAG_OPTION1 | UAG_OPTION2 | UAG_OPTION3 : 111

Et bien c'est justement ça le principe des opérateurs bitwise : ils opèrent sur la représentation binaire des entiers, plutôt que sur leur valeur dans le système décimal. C'est un peu perturbant au début car un esprit humain ordinaire n'est pas habitué à manipuler les nombres en binaire, mais en réalité c'est assez simple, il suffit d'imaginer un "tableau" avec chaque option sur une colonne (chaque colonne est appelée un bit).

Voici les 3 opérateurs les plus utiles :

Opérateurs bitwise PHP les plus utiles
Opérateur Nom Description
$a & $b ET Les bits positionnés à 1 dans $a ET dans $b sont positionnés à 1
$a | $b OU Les bits positionnés à 1 dans $a OU $b sont positionnés à 1
~ $a NOT Les bits qui sont positionnés à 1 dans $a sont positionnés à 0, et vice-versa

Pour plus d'infos sur les autres opérateurs bitwise, consultez la documentation officielle : language.operators.bitwise.

Les opérateurs binaires sont utilisés dans la configuration de php (php.ini) notamment au niveau de la directive error_reporting.

Afficher un nombre en binaire en PHP

Voilà une petite astuce pour afficher la valeur d'un nombre entier sous forme binaire : il suffit d'utiliser la fonction decbin($nombre).

Allez donc jeter un oeil sur cette page : mode protégé sur excel.

Un exemple avec une classe

Ci-dessous, un petit exemple de l'utilisation des opérateurs bitwise sur une classe comportant une fonction transform qui permet d'effectuer différents traitements sur une chaine de caractère. On va placer cette fonction dans une classe, dans laquelle on va définir chaque option dans une constante de classe :

  • noAccent : remplacer les caractères accentués par leur version "sans accent"
  • addLink : remplace les URL (ex: http://www.finalclap.com/) par un lien hypertexte HTML : <a href="http://www.finalclap.com/">http://www.finalclap.com/</a>

J'ai aussi ajouté quelques méthodes permettant de savoir si tel ou tel option est activée ou pas, pour vous montrer comment utiliser les opérateurs bitwise.

Bon, ça reste un exemple, cette classe ne sert pas à grand-chose...

class TextTool
{
	const noAccent = 1; // 0000000000000000000000000000001
	const addLink  = 2; // 0000000000000000000000000000010
	
	public static $defaultOptions = 0; // Aucune option activée par défaut
	
	public static function transform($text, $options = null){
		// Options par défaut
		if( $options === null ){
			$options = self::$defaultOptions;
		}
		
		// Remplacement des caractères accentués
		if( self::enabled(self::noAccent, $options) ){
			$accents   = 'àáâãäçèéêëìíîïñòóôõöùúûüýÿÀÁÂÃÄÇÈÉÊËÌÍÎÏÑÒÓÔÕÖÙÚÛÜÝ';
			$noaccents = 'aaaaaceeeeiiiinooooouuuuyyAAAAACEEEEIIIINOOOOOUUUUY';
			$text = utf8_encode(strtr(utf8_decode($text), utf8_decode($accents), $noaccents));
		}
		
		// Ajout des tag <a> pour les URL
		if( self::enabled(self::addLink, $options) ){
			$text = preg_replace('@([^>"])(https?://[a-z0-9\./+,%#_-]+)@i', '$1<a href="$2">$2</a>', $text);
		}
		
		return $text;
	}
	
	// Active l'option $option dans le set $options
	public static function enable($option, $options = 0){
		return $options | $option;
	}
	
	// Désactive l'option $option dans le set $options
	public static function disable($option, $options = 0){
		return $options & ~$option;
	}
	
	// Indique si l'option $option est activée dans $options
	public static function enabled($option, $options = 0){
		return $options & $option ? true : false;
	}
}

Maintenant il ne reste qu'à utiliser cette classe :

// Affiche un entier 32bit sous forme binaire
function binview($value){
	$result = decbin(0 | $value);
	$result = str_pad($result, 32, '0', STR_PAD_LEFT);
	echo $result."\n";
}

header('Content-Type: text/plain; charset=utf-8');

// Savoir si une extension est activée
echo "Savoir si une extension est activée\n"
	."===================================\n";
$options = TextTool::addLink;
echo "noAccent: "; var_dump( TextTool::enabled(TextTool::noAccent, $options) );
echo "addLink:  "; var_dump( TextTool::enabled(TextTool::addLink, $options) );
echo "\nVersion binaire :\n";
binview($options);
echo "\n";

// Activer des options
echo "Activer des options\n"
	."===================\n";
$options = TextTool::enable(TextTool::noAccent, $options);
$options = TextTool::enable(TextTool::addLink, $options);
binview($options);
echo "\n";

// Désactiver des options
echo "Désactiver des options\n"
	."======================\n";
$options = TextTool::disable(TextTool::noAccent, $options);
binview($options);
echo "\n";

// Utiliser les opérateurs bitwise comme options
echo "Utiliser les opérateurs bitwise comme options\n"
	."=============================================\n";

$text = "<p>Les meilleurs tuto sont é sur http://www.finalclap.com/ !</p>";
echo TextTool::transform($text, TextTool::noAccent | TextTool::addLink);

Voilà le résultat :

Savoir si une extension est activée
===================================
noAccent: bool(false)
addLink:  bool(true)

Version binaire :
00000000000000000000000000000010

Activer des options
===================
00000000000000000000000000000011

Désactiver des options
======================
00000000000000000000000000000010

Utiliser les opérateurs bitwise comme options
=============================================
<p>Les meilleurs tuto sont e sur <a href="http://www.finalclap.com/">http://www.finalclap.com/</a> !</p>

Allez donc jeter un oeil sur cette page : dessiner bob l'éponge.

0 commentaire
facultatif
Facebook Twitter RSS Email
Forum Excel
Venez découvrir le nouveau forum excel question/réponse à la stackoverflow.com !
Forum Excel
hit parade n'en a rien a foutre du W3C Positionnement et Statistiques Gratuites Vincent Paré