16 Stimmen

C UND PHP: Speichern von Einstellungen in einer Ganzzahl mit bitweisen Operatoren?

Ich bin mit bitweisen Operatoren nicht vertraut, aber ich habe sie schon einmal zum Speichern einfacher Einstellungen verwendet gesehen.

Ich muss mehrere Ein/Aus-Optionen an eine Funktion übergeben, und ich möchte eine einzelne Ganzzahl dafür verwenden. Wie kann ich diese Optionen einstellen und auslesen?

37voto

Peter Bailey Punkte 103278

In PHP können Sie das sicher tun.

Angenommen, Sie haben vier Boolesche Werte, die Sie in einem einzigen Wert speichern möchten. Das bedeutet, dass wir vier Bits an Speicherplatz benötigen

0000

Jedes Bit, wenn es einzeln gesetzt wird, hat eine eindeutige Darstellung in Dezimalzahlen

0001 = 1 // or 2^0
0010 = 2 // or 2^1
0100 = 4 // or 2^2
1000 = 8 // or 2^3

Eine gängige Methode zur Umsetzung ist die Verwendung von Bitmasken zur Darstellung jeder Option. Die PHP-Fehlerstufen werden zum Beispiel auf diese Weise realisiert.

define( 'OPT_1', 1 );
define( 'OPT_2', 2 );
define( 'OPT_3', 4 );
define( 'OPT_4', 8 );

Wenn Sie dann eine ganze Zahl haben, die 0 oder mehr dieser Flags darstellt, prüfen Sie mit dem bitweisen und-Operator, der lautet &

$options = bindec( '0101' );
// can also be set like this
// $options = OPT_1 | OPT_3;

if ( $options & OPT_3 )
{
  // option 3 is enabled
}

Dieser Operator funktioniert folgendermaßen: nur Bits, die in beiden Operanden gesetzt sind, werden auch im Ergebnis gesetzt

0101 // our options
0100 // the value of OPT_3
----
0100 // The decimal integer 4 evaluates as "true" in an expression

Wenn wir es mit OPT_2 dann würde das Ergebnis wie folgt aussehen

0101 // our options
0010 // the value of OPT_2
----
0000 // The decimal integer 0 evaluates as "false" in an expression

8voto

Tim Post Punkte 32750

Es funktioniert in beiden Sprachen in etwa gleich, ein Vergleich nebeneinander:

C:

#include <stdio.h>
#include <stdint.h>

#define FLAG_ONE 0x0001
#define FLAG_TWO 0x0002
#define FLAG_THREE 0x0004
#define FLAG_FOUR 0x0008
#define FLAG_ALL (FLAG_ONE|FLAG_TWO|FLAG_THREE|FLAG_FOUR)

void make_waffles(void)
{
   printf("Yummy! We Love Waffles!!!\n");
}

void do_something(uint32_t flags)
{
    if (flags & FLAG_TWO)
         make_waffles();
}

int main(void)
{
    uint32_t flags;

    flags |= FLAG_ALL;

    /* Lets make some waffles! */
    do_something(flags);

    return 0;
}

PHP:

<?php

define("FLAG_ONE", 0x0001);
define("FLAG_TWO", 0x0002);
define("FLAG_THREE", 0x0004);
define("FLAG_FOUR", 0x0008);
define("FLAG_ALL", FLAG_ONE|FLAG_TWO|FLAG_THREE|FLAG_FOUR);

function make_waffles()
{
    echo 'Yummy! We Love Waffles!!!';
}

function do_something($flags)
{
    if ($flags & FLAG_TWO)
       make_waffles();
}

$flags |= FLAG_TWO;
do_something($flags);

?>

Beachten Sie, dass Sie nicht unbedingt Konstanten verwenden müssen, ich verwende sie nur aus Gewohnheit. Beide Beispiele sind lauffähig, ich habe die C-Version über gcc -Wall flags.c -o flags . Ändern Sie flags in beiden Beispielen zu etwas anderem als FLAG_TWO o FLAG_ALL und (leider) werden keine Waffeln gebacken.

In der C-Version müssen Sie nicht den Präprozessor kitzeln müssen, es könnte ganz einfach eine Aufzählung sein, usw. - das ist eine Übung für den Leser.

2voto

Andrey Punkte 57704

Zitat "die idee ist nicht gut, wirklich. sie würden besser übergeben einige boolesche. wenn sie wollen, verwenden sie bitweise dann

function someFunc($options)
{

   if ($options & 1 != 0)
      //then option 1 enabled
   if ($options & (1 << 1) != 0)
      //then option 2 enabled      
   if ($options & (1 << 2) != 0)
      //then option 3 enabled      
}

"

Was Sie getan haben, wäre in Ordnung, wenn Sie für einen einzelnen Wert überprüfen, obwohl nicht optimal, so überprüfen, dass ein Bit aktiviert ist, aber sagen wir, wir wollten in der Lage sein, alle übereinstimmen, oder genau könnten wir die folgenden Methoden haben

function matchExact($in, $match) { // meets your criterion, as would a switch, case, but ultimately not suited for use with flags
    return $in === $match;
}

function matchAny($in, $match) { // meets original criterion with more lexical name however it returns true if any of the flags are true
    return $in |= $match;
}

Wenn Sie dies noch erweitern möchten, indem Sie bestimmte Aktionen nur dann durchführen, wenn Bit x,y,z aktiviert ist, könnten Sie Folgendes verwenden

function matchHas($in, $match) { // more bitwise than === as allows you to conditionally branch upon specific bits being set
    return $in &= $match;
}

Ich denke auch, wenn Sie das tun, was in dem obigen Zitat getan wurde, sind Flaggen vielleicht nicht die beste Idee, exakte Werte könnten besser sein, was den Vorteil hat, dass es diskretere Aktionen ermöglicht. (0-255) für 8-Bit über 8 verschiedene Flaggen

Flaggen funktionieren nur deshalb so gut, weil zur Basis 2 "8" keine "4" und "2" keine "1" enthält.

 \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
 |8|4|2|1|Base 10 Value |
 ------------------------
 |1|1|1|1|15            |
 |1|1|1|0|14            |
 |1|1|0|1|13            |
 |1|1|0|0|12            |
 |1|0|1|1|11            |
 |1|0|1|0|10            |
 |1|0|0|1|9             |
 |1|0|0|0|8             |
 |0|1|1|1|7             |
 |0|1|1|0|6             |
 |0|1|0|1|5             |
 |0|1|0|0|4             |
 |0|0|1|1|3             |
 |0|0|1|0|2             |
 |0|0|0|1|1             |
 |0|0|0|0|0             |
 ------------------------

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X