29. Oktober 2012

Bitfelder/Bitfields mit PHP

29. Oktober 2012 - Geschrieben von Martin - Keine Kommentare

Heute beschäftigte ich mich damit Bitfelder in PHP abzubilden. In meinem Fall wurde eine Variable mit verschiedenen Flags befüllt. Am altbekannten
OOP Beispiel Auto könnten diese Flags zum Beispiel Ausstattungsmerkmale sein:

  • Panoramadach? Ja/Nein
  • Navigationssystem? Ja/Nein
  • Alufelgen? Ja/Nein

Um diese Werte nun besondern Speicherplatzschonend zu sparen, wollen wir nun alles in ein Bitfeld speichern. Ein Bitfield mit Flags ist eigentlich nur eine Folge von Nullen, auf der Bits gesetzt (0 –> 1) werden können.

Beispielsweise hat unser Auto die Merkmale Panoramadach und Alufelgen, dann sieht dieses Bitfield so aus:

101

Gelesen wird die Ausstattungsmerkmalliste von oben nach unten und das Bitfeld von rechts nach links. Die erste 1 sagt, ja wir haben ein Panoramadach, die 0 sagt Nein wir haben kein Navigationssystem und die zweite 1 ganz links verrät Ja wir haben Alufelgen.

Mit PHP können wir dieses Bitfield so erzeugen:

$bitfield;
$bitfield |= 1 << 0; // An die erste (also 0te) Stelle im Bitfield eine 1 setzen
$bitfield |= 0 << 1; // An die zweite eine 0
$bitfield |= 1 << 2; // Und an die dritte eine 1

In der zweiten Codezeile gibt die 1 an, dass das Bit gesetzt ist, das „<<" setzt dann diesen Vorrausgehenden Wert auf die nachfolgende Stelle (in dem Fall 0) im Bitfeld.

0 << 0 // erstes Bit ist Null
0 << 1 // zweites Bit ist Null
0 << 2 // drittes Bit ist Null
1 << 3 // viertes Bit ist Eins
1 << 4 // fünftes Bit ist Eins

Nun können wir uns mit folgender Funktion die Binärzahl ausgeben lassen:

echo base_convert($bitfields, 10, 2);

Dieser Funktionsaufruf konvertiert die Zahl von der Basis 10 zur Basis 2 und gibt sie aus:

101

Passt. Nun können wir noch prüfen, ob z.B. das erste Bit gesetzt ist:

if($bitfield & 1 << 0)
    echo 'Das erste Bit ist gesetzt.';

Hier wird geprüft, ob das gesetzte Bit in der Bitfield Variable und „1 << 0" gleich sind. Wenn ja ergibt der Ausdruck true. Damit das ganze halbwegs dynamisch bleibt und man nicht immer die Bitzuweisung von Hand tippen muss, so können wir diese auch in einer Varibale oder Konstante speichern:

define('MERKMAL_PANORAMADACH', 1 << 0);
define('MERKMAL_NAVIGATIONSSYSTEM', 0 << 1);
define('MERKMAL_ALUFELGEN', 1 << 2);
 
$bitfield;
$bitfield |= MERKMAL_PANORAMADACH;
$bitfield |= MERKMAL_NAVIGATIONSSYSTEM;
$bitfield |= MERKMAL_ALUFELGEN;
 
if($bitfield & MERKMAL_ALUFELGEN)
    echo 'Jep, das Auto hat Alufelgen.';