Nachdem meine PHP-Tutorials zwar relativ hohen Anklang gefunden haben aber dennoch hier und da der Ruf nach Fortgeschrittenen-Tutorials aufkam, gibt's jetzt hier mal nen kleinen Abstecher außer der Reihe.
Hinweise: Dieses Tutorial ist an Fortgeschrittene gerichtet. Ich gehe davon aus, dass ihr mit den Basics numerischer Systeme (in diesem Fall dem binären Zahlensystem) bereits vertraut seit.
Achtung: Wir betreten hier Bereiche boolescher Algebra...
Also, fangen wir am Anfang an:
Was sind eigentlich Bit-Operatoren?
Im Grunde sind Bit-Operator nichts anders als logische Operatoren, wie ich sie bereits in Lektion 3 vorgestellt habe. Dabei steht die binäre 1 jeweils für true und die 0 entsprechend für false.
Der OR-Operator
Beginnen wir also mit dem Operator "OR", der in PHP mit einer sog. Piper (= | ) notiert wird:
<?php
if (5 | 9 == 13)
{
// doStuff();
}
?>
Der OR-Operator überprüft ob einer der beiden Operanden gegeben (=true =1) ist. Um den Vorgang verstehen zu können, müssen wir die beiden Operanden 5 und 9 in das binäre Zahlensystem übersetzen.
Dabei erhalten wir 101 und 1001.
Die Operation
0101 1001 ----- OR: 1101 = 13 (dec)
Der Reihe nach: Die hier übereinander stehenden Werte werden einzeln verglichen.
Von rechts nach links ergibt sich also:
- 1 OR 1 = 1
(weil Operand 1 gegeben) - 0 OR 0 = 0
(weil keiner der Operanden gegeben) - 1 OR 0 = 1
(weil Operand 1 gegeben) - 0 OR 1 = 1
(weil Operand 2 gegeben)
Der AND-Operator
Der Bit-Operator AND wird in PHP mit & notiert:
<?php
if (5 & 9 == 1)
{
// doStuff();
}
?>
Der AND-Operator ergibt true, also 1, wenn beide Operatoren gegeben sind.Wir schreiben wieder um nach binär und haben...
Die Operation
0101 1001 ----- AND: 0001 = 1 (dec)
Es ergibt sich:
- 1 AND 1 = 1
(weil Operand 1 UND Operand 2 gegeben) - 0 AND 0 = 0
(weil kein Operand gegeben) - 1 AND 0 = 0
(weil nur ein Operand gegeben) - 0 AND 1 = 0
(weil nur ein Operand gegeben)
XOR steht für "exklusives ODER", was sich etwa mit "entweder oder" übersetzen lässt. XOR wird als Bit-Operator in PHP wie folgt notiert:
<?php
if (5 ^ 9 == 12)
{
// doStuff();
}
?>
Die Operation
0101 1001 ---- XOR: 1100 = 12 (dec)
Im einzelnen:
- 1 XOR 1 = 0
(weil beide Operanden gegeben) - 0 XOR 0 = 0
(weil kein Operand gegeben) - 1 XOR 0 = 1
(weil genau ein Operand gegeben) - 0 XOR 1 = 1
(weil genau ein Operand gegeben)
Daneben gibt es noch den Negationsoperator "NOT", der in PHP mit der Tilde (= ~ ) notiert wird. Hierauf werde ich jetzt aber nicht im einzelnen eingehen. Stattdessen schauen wir uns folgendes kombiniertes Beispiel an:
<?php
if (~(5 & 9) == (~5 | ~9))
{
// doStuff();
}
?>
Hinweis: Die folgende Erklärung ist für das Verständnis, NICHT wie es eigentlich funktioniert (siehe unten)
Diese Operation entspricht in Worten:
if NOT (5 AND 9) equals (NOT 5 OR NOT 9)
Das Ergebnis ist true und ich werde euch zeigen warum.
Operation 1: 5 & 9
0101 1001 ---- AND: 0001 = 1 (dec)
Negation des Ergebnisses von Operation 1Damit haben wir auf der linken Seite schonmal das Ergebnis 14 (in dezimal). Also weiter mit der rechten Hälfte...
0001 ---- NOT: 1110 = 14 (dec)
Negation von 5
0101 ----- NOT: 1010 = 10 (dec)
Negation von 9
1001 ----- NOT: 0110 = 6 (dec)
Operation 2: ~5 OR ~9Wir sehen also, dass das negierte Ergebnis einer AND-Operation gleich dem Ergebnis einer OR-Operation mit negierten Operanden ist, sofern die Operanden selbst identisch sind. Ich hab euch ja gewarnt: boolesche Algebra ;-)
1010 0110 ---- OR: 1110 = 14 (dec)
Probleme
Das obige Beispiel diente wie gesagt nur zur Veranschaulichung. ~5 ergibt nämlich effektiv -6.
Warum ist das so?
Naja, Integer-Werte sind in PHP immer in 32bin. D.h. 5 ist eigentlich
0000.0000.0000.0000.0000.0000.0000.0101
und negiert
1111.1111.1111.1111.1111.1111.1111.1010
Ihr denkt vielleicht, dass das in dezimal 4.294.967.290 ergeben müsste, womit ihr auch eigentlich Recht hättet.
Aber: Das erste Bit (ganz links) kündigt eine negative Zahl an, wenn gesetzt. Dieses Bit wird "extra bit" genannt — sehr kreativ, ich weiß… ;-) Dann werden die Zahlen rückwärts gezählt, was -6 ergibt.
Eigentlich wären es -5, aber da es kein -0 gibt beginnen wir unsere Zählung mit -1.
Aber was, wenn wir den erwarteten Wert 2 wollen, da 101 negiert 010 ergibt?
Die Algebra lässt grüßen, wir brauchen lediglich ein kleines AND.
Sagen wir also, wir wollen zwei Ziffern, dann müssen wir es mit 11 (bin) (= 3(dec)) "ANDen".
Also haben wir ~5 & 3
Schauen wir uns das mal an
Wir haben also ~5, das 1111.1111.1111.1111.1111.1111.1111.1010 ist
und 3, was in binär 0000.0000.0000.0000.0000.0000.0000.0011 ist.
Unser AND:
1111.1111.1111.1111.1111.1111.1111.1010
0000.0000.0000.0000.0000.0000.0000.0011
Das Ergebnis ist 0000.0000.0000.0000.0000.0000.0000.0010, was 2 (dec) ist.
Tada!
Also wofür braucht man das noch gleich?
Nun, PHP selbst verwendet Bit-Operationen für einen kleinen Trick. Schauen wir uns hierzu mal die Fehlerkonstanten (E_ALL usw.) an. Diese Konstanten besitzen Integerwerte:
E_ERROR = 1
E_WARNING = 2
E_PARSE = 4
E_NOTICE = 8
E_CORE_ERROR = 16
E_CORE_WARNING = 32
E_COMPILE_ERROR = 64
E_COMPILE_WARNING = 128
E_USER_ERROR = 256
E_USER_WARNING = 512
E_USER_NOTICE = 1024
E_STRICT = 2048
E_RECOVERABLE_ERROR = 4096
E_DEPRECATED = 8192
E_USER_DEPRECATED = 16384
E_ALL = 30719
Fällt euch was auf? Nun, der Standardwert (seit PHP5, glaub ich) ist E_ALL & ~E_NOTICE, was 30711 ergibt.Oder auch E_ALL ^ E_NOTICE (^ ist in dem Fall etwa "außer") was wieder 30711 ergibt.
Das macht die Fehlerkonfiguration auf eine gewisse Art "sprechbar".
Hier ist noch ein Beispiel: E_ERROR | E_WARNING gibt 3. Also bedeutet 3 "zeige Fehler und (OR) Warnungen".
Beachtet: Wir verwenden nicht den &-Operator, da E_ERROR & E_WARNING z.B. 0 ergibt, genauso wie E_WARNING & E_NOTICE.
Also haben sich die Jungs von PHP für den OR-Operator entschieden.
Okay, auf php.net, sagen sie über E_ALL "Alle Fehler und Warnungen die unterstützt werden, mit Ausnahme von E_STRICT."
Wir haben also:
E_ERROR | E_WARNING | E_PARSE | E_NOTICE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING | E_USER_ERROR | E_USER_WARNING | E_USER_NOTICE | E_RECOVERABLE_ERROR | E_DEPRECATED | E_USER_DEPRECATED
Das Ergebnis ist — wer hätt's gedacht — E_ALL = 30719
Es gibt viele weitere vorstellbare Wege, das sinnvoll einzusetzen.
Schlusswort
So, das war's. Ich hoffe, es war nicht alles umsonst und ich konnte vllt. jemandem den Tag retten oder so.
Bei Fragen: Comments, comments, comments — ich antworte gerne :)
Feedback is btw. auch immer sehr erwünscht. Nur so kann ich daran arbeiten, dass meine Tutorials in Zukunft besser werden :)
Nicht, dass sie so schon überragend wären *öhöm* ;-)
Grüße,
euer Outliver


Kommentare
Kommentieren