Arguments de fonction en tant que constantes de bits en PHP

Bonjour, Habr! Je vous présente la traduction d'un article de Liam Hammett : Bitmask Constant Arguments en PHP .

PHP contient de nombreuses fonctions standard qui acceptent les arguments booléens sous la forme de constantes intégrées avec des nombres binaires.
Ces valeurs sont combinées en un seul argument de la fonction afin de transférer plusieurs drapeaux booléens de manière compacte.


Ils peuvent fonctionner un peu différemment de ce que beaucoup de gens imaginent et utilisent dans leur code, donc je suggère de considérer comment cela fonctionne vraiment.




Comment il est utilisé dans les fonctions PHP


PHP 7.2, y compris les extensions, contient plus de 1800+ constantes prédéfinies, et certaines d'entre elles sont utilisées comme arguments pour les fonctions.
Un exemple d'une telle application est une nouvelle option en PHP 7.3, qui vous permet de json_encode une exception de la fonction json_encode pour les erreurs de conversion.


 json_encode($value, JSON_THROW_ON_ERROR); 

Utilisation | (ou) au niveau du bit, plusieurs arguments de fonction fonctionnent comme un seul. Un exemple tiré de la documentation PHP:


 json_encode($value, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP | JSON_UNESCAPED_UNICODE); 

Rien du tout.


Mais comment ça marche?


L'application d'opérations au niveau du bit pour obtenir le même effet dans le monde des fonctions définies par l'utilisateur est en fait simple, mais elle nécessite au moins une connaissance de base de ce que sont les bits et de la façon dont les opérations au niveau du bit fonctionnent en PHP.


Les entiers peuvent être spécifiés dans un système de nombres décimal (base 10), hexadécimal (base 16), octal (base 8) ou binaire (base 2). [...]
Pour écrire en notation binaire, vous devez mettre avant le nombre 0b.
- php.net

Exemples de constantes avec un ensemble différent de nombres binaires:


 const A = 0b0001; // 1 const B = 0b0010; // 2 const C = 0b0100; // 4 const D = 0b1000; // 8 

Faites attention à l'exemple et à la séquence des nombres. Chaque valeur binaire représente une valeur deux fois plus élevée pour chaque zéro à la fin. Les zéros compris entre 0b et 1 sont facultatifs, mais peuvent aider à aligner le code source.


Heureusement, nous devons comprendre comment ne fonctionnent que deux opérations au niveau du bit.


OU au niveau du bit


Ne confondez pas l'opérateur | ( "OR" au niveau du bit ) avec l'opérateur fréquemment utilisé || ( "OR" logique ), qui se trouve généralement dans les if else .
Le «OU» au niveau du bit est une opération binaire dont l'action équivaut à appliquer un «OU» logique à chaque paire de bits situés aux mêmes positions dans les représentations binaires des opérandes. En d'autres termes, si les deux bits correspondants des opérandes sont 0, le bit binaire du résultat est 0; si au moins un bit de la paire est 1, le bit binaire du résultat est 1.


Exemple d'opération bit à bit "OU":


 const A = 0b0001; const B = 0b0010; const C = 0b0100; const D = 0b1000; A | B === 0b0011; A | C | D === 0b1101; 

ET au niveau du bit (ET)


De même, l'opérateur & ( AND au niveau du bit ) ne doit pas être confondu avec l'opérateur && fréquemment utilisé ( AND logique ).
Un ET au niveau du bit est une opération binaire dont l'action équivaut à appliquer un ET logique à chaque paire de bits situés aux mêmes positions dans les représentations binaires des opérandes. En d'autres termes, si les deux bits correspondants des opérandes sont à 1, le bit binaire résultant est à 1; si au moins un bit de la paire est 0, le bit binaire résultant est 0.


 const A = 0b0001; const B = 0b0010; const C = 0b0100; const D = 0b1000; const VALUE = 0b1010; A & B === 0b0000; //      A  B A & C & D === 0b0000; //      A, B  C A & A === 0b0001; //      A  A & VALUE === 0b0000; //      A  VALUE B & VALUE === 0b0010; //  1    B,    VALUE 

Un nombre peut-il avoir un booléen?


Il est à noter qu'en PHP il y a le concept de " manipulation de type" ( jonglage de type ). Dans le langage des non-experts, cela signifie qu'il (PHP) tentera automatiquement de convertir les données d'un type à un autre, si nécessaire.
Si vous comprenez comment ces transformations se produisent, cela peut être un outil utile.
Par exemple, nous savons que le nombre 0 agit comme false lors de la conversion en booléen, tandis que tous les autres nombres seront true . Rappelez-vous que ces valeurs binaires avec lesquelles nous travaillons sont en fait des entiers?


Pour résumer!


Maintenant, nous pouvons combiner ces connaissances pour créer une construction if, le code dans lequel sera exécuté uniquement si le résultat de l'opération au niveau du bit entre les nombres n'est pas 0b0000 (ou 0 , qui est converti en false ).


 const A = 0b0001; const B = 0b0010; function f($arg = 0) { if ($arg & A) { echo 'A'; } if ($arg & B) { echo 'B'; } } f(); // nothing f(A); // 'A' f(B); // 'B' f(A | B); // 'AB' 

D'autres fonctions PHP intégrées (comme json_encode ) fonctionnent de la même manière.


Est-ce que ça vaut le coup?


Vous souhaitez peut-être maintenant appliquer cette approche pour les fonctions avec un grand nombre d'arguments qui participent aux constructions conditionnelles, mais il existe un certain nombre d'inconvénients dans le traitement des indicateurs de fonction au niveau du bit:


  • Vous ne pouvez pas transmettre de valeurs non booléennes via un argument.
  • Il n'existe aucun moyen standard de documenter les arguments à l'aide de docblocks.
  • Vous perdez des conseils généraux et le support de la plupart des IDE.
  • Au lieu de cela, vous pouvez passer un tableau associatif comme argument pour pouvoir définir des valeurs non nulles (ou même une classe ).
  • Il y a de bonnes raisons pour lesquelles vous devriez éviter d'utiliser des «indicateurs de fonction» logiques comme arguments et utiliser à la place une autre fonction ou méthode pour une fonctionnalité modifiable.

Cependant, vous savez maintenant comment procéder.




La lecture d'une longue liste de définitions de constantes peut être verbeuse et difficile, voici donc une fonction auxiliaire qui simplifie leur définition.

Source: https://habr.com/ru/post/fr423257/


All Articles