Funktionsargumente als Bitkonstanten in PHP

Hallo Habr! Ich präsentiere Ihnen die Übersetzung eines Artikels von Liam Hammett : Bitmask Constant Arguments in PHP .

PHP enthält viele Standardfunktionen, die boolesche Argumente in Form von integrierten Konstanten mit Binärzahlen akzeptieren.
Diese Werte werden zu einem einzigen Argument der Funktion zusammengefasst, um mehrere Boolesche Flags auf kompakte Weise zu übertragen.


Sie funktionieren möglicherweise etwas anders, als sich viele Menschen in ihrem Code vorstellen und verwenden. Ich schlage daher vor, darüber nachzudenken, wie es wirklich funktioniert.




Wie es in PHP-Funktionen verwendet wird


PHP 7.2, einschließlich Erweiterungen, enthält über 1800 vordefinierte Konstanten, von denen einige als Argumente für Funktionen verwendet werden.
Ein Beispiel für eine solche Anwendung ist eine neue Option in PHP 7.3, mit der Sie eine Ausnahme von der Funktion json_encode für Konvertierungsfehler json_encode können.


 json_encode($value, JSON_THROW_ON_ERROR); 

Verwenden von | (oder) bitweiser Operator, mehrere Funktionsargumente arbeiten als eines. Ein Beispiel aus der PHP-Dokumentation:


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

Gar nichts.


Aber wie funktioniert es trotzdem?


Das Anwenden von bitweisen Operationen, um den gleichen Effekt in der Welt der benutzerdefinierten Funktionen zu erzielen, ist eigentlich einfach, erfordert jedoch mindestens Grundkenntnisse darüber, was Bits sind und wie bitweise Operationen in PHP funktionieren.


Ganzzahlen können in Dezimalzahl (Basis 10), Hexadezimalzahl (Basis 16), Oktalzahl (Basis 8) oder Binärzahl (Basis 2) angegeben werden. [...]
Um in binärer Notation zu schreiben, müssen Sie vor die Zahl 0b setzen.
- php.net

Beispiele für Konstanten mit einem anderen Satz von Binärzahlen:


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

Achten Sie auf das Beispiel und die Reihenfolge der Zahlen. Jeder Binärwert repräsentiert einen doppelt so hohen Wert für jede Null am Ende. Nullen zwischen 0b und 1 sind optional, können jedoch zur Ausrichtung des Quellcodes beitragen.


Glücklicherweise müssen wir verstehen, wie nur zwei bitweise Operationen funktionieren.


Bitweises ODER


Verwechseln Sie den Bediener nicht ( bitweises "ODER" ) mit dem häufig verwendeten Operator || ( logisches "ODER" ), das normalerweise in if else .
Das bitweise "ODER" ist eine binäre Operation, deren Aktion dem Anwenden eines logischen "ODER" auf jedes Bitpaar entspricht, das sich an denselben Positionen in den binären Darstellungen der Operanden befindet. Mit anderen Worten, wenn beide entsprechenden Bits der Operanden 0 sind, ist das Binärbit des Ergebnisses 0; Wenn mindestens ein Bit aus dem Paar 1 ist, ist das Binärbit des Ergebnisses 1.


Beispiel für eine bitweise Operation "ODER":


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

Bitweises UND (UND)


Ebenso sollte der Operator & ( bitweises UND ) nicht mit dem häufig verwendeten Operator && ( logisches UND ) verwechselt werden.
Ein bitweises UND ist eine binäre Operation, deren Aktion dem Anwenden eines logischen UND auf jedes Bitpaar entspricht, das sich an denselben Positionen in den binären Darstellungen der Operanden befindet. Mit anderen Worten, wenn beide entsprechenden Bits der Operanden 1 sind, ist das resultierende Binärbit 1; Wenn mindestens ein Bit aus dem Paar 0 ist, ist das resultierende Binärbit 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 

Kann eine Zahl einen Booleschen Wert haben?


Es ist erwähnenswert, dass es in PHP das Konzept der " Typmanipulation " ( Typ-Jonglieren ) gibt. In der Sprache von Nicht-Experten bedeutet dies, dass es (PHP) bei Bedarf automatisch versucht, Daten eines Typs in einen anderen zu konvertieren.
Wenn Sie verstehen, wie solche Transformationen ablaufen, kann dies ein nützliches Werkzeug sein.
Zum Beispiel wissen wir, dass die Zahl 0 bei der Konvertierung in einen Booleschen Wert als false fungiert, während alle anderen Zahlen true . Denken Sie daran, dass diese Binärwerte, mit denen wir arbeiten, tatsächlich ganze Zahlen sind?


Zusammenfassend!


Jetzt können wir dieses Wissen kombinieren, um ein if-Konstrukt zu erstellen, dessen Code nur ausgeführt wird, wenn das Ergebnis der bitweisen Operation zwischen Zahlen nicht 0b0000 (oder 0 , das in false konvertiert wird).


 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' 

Andere integrierte PHP-Funktionen (wie json_encode ) funktionieren genauso.


Lohnt es sich?


Vielleicht möchten Sie diesen Ansatz jetzt auf Funktionen mit einer großen Anzahl von Argumenten anwenden, die an bedingten Konstruktionen beteiligt sind, aber die Verarbeitung bitweiser Funktionsflags weist eine Reihe von Nachteilen auf:


  • Sie können keine nicht-booleschen Werte über ein Argument übergeben.
  • Es gibt keine Standardmethode, um Argumente mit docblocks zu dokumentieren.
  • Sie verlieren allgemeine Hinweise und Unterstützung für die meisten IDEs.
  • Stattdessen können Sie ein assoziatives Array als Argument übergeben, um Werte ungleich Null (oder sogar eine Klasse ) festlegen zu können.
  • Es gibt gute Gründe, warum Sie die Verwendung logischer „Funktionsflags“ als Argumente vermeiden und stattdessen eine andere Funktion oder Methode für veränderbare Funktionen verwenden sollten.

Jetzt wissen Sie jedoch, wie es geht.




Das Lesen einer langen Liste von Definitionen von Konstanten kann ausführlich und schwierig sein. Hier ist eine Hilfsfunktion, die ihre Definition vereinfacht.

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


All Articles