Les opérateurs bitwise
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é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.