php.de

Zurück   php.de > php.de Intern > Wiki Diskussionsforum > Tutorials

Tutorials Hier findest Du Tutorials, welche nach und nach ein fertiges Script ergeben. Sehen, lernen & verstehen!

Antwort
 
LinkBack Themen-Optionen Thema bewerten
Alt 18.07.2007, 20:06  
moderatives Dielektrikum
 
Benutzerbild von nikosch
 
Registriert seit: 21.05.2008
Beiträge: 35.994
PHP-Kenntnisse:
Fortgeschritten
nikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunft
Standard Funktions-Flags verarbeiten

Inspiriert von Zerglings letzter Frage zu Bitmasken, möchte ich ein paar Grundlagen zu Dualzahlen und deren Verwendung als Flag zum Besten geben.

Die meisten werden bei der Arbeit mit PHP schon die Bekanntschaft mit Flags gemacht haben. Sie werden oft benutzt, um das Verhalten von Funktionen mit hinter aussagekräftigen Konstantennamen definierten Werten zu beeinflussen. Dabei können meist mehrere Konstanten durch | (Pipe) kombiniert werden.

Hinter diesem Verfahren steckt ein einfaches Prinzip: die Stelle, an der bei Funktionsaufruf keine, eine oder eine Anzahl mit Pipe verknüpfter Konstanten angegeben wird, erwartet eigentlich einen ganz normalen Funktionsparameter, speziell einen Binärwert. Die zugehörigen Konstanten werden ebenfalls als Binärzahlen definiert, jede entspricht dabei einem anderen ganzzahligen Exponenten (Das kann man gut sehen, wenn man sich die Konstanten einer beliebigen Funktion mit Flags einfach mal ausgeben läßt). Das Pipe Symbol ist dann schlichtweg der Bit-Operator für 'ODER'.

Ein Beispiel:
Wir haben eine Funktion, die verschiedene Arbeitsweisen bietet, gesteuert von 4 Konstanten oder deren Kombination. Wir nennen diese Zustände mal AA, BB, CC und DD. Jeder dieser Zustände wird nun als Konstante mit einer Zahl aus dem Binärsystem belegt:

Code:
AA - 1
BB - 2
CC - 4
DD - 8
Jede Zahl ist als doppelter Wert der vorhergehenden definiert, das entspricht aufsteigenden, ganzzahligen Exponenten im Binärsystem, oder ums plastischer zu machen:

Code:
AA - binär 0001  = 2 hoch 0
BB - binär 0010  = 2 hoch 1
CC - binär 0100  = 2 hoch 2
DD - binär 1000  = 2 hoch 3
Stellen wir uns nun vor, wir wollen eine beliebige Kombination dieser 4 Zustände angeben und schauen wir uns dazu die binäre Darstellung der einzelnen Werte an, so wird schnell ersichtlich, dass jeder Zustand seine 'eigene' Dualstelle besitzt, die ihn als An (1) oder Aus (0) kennzeichnen kann.

Binär 1010 wäre demzufolge die Schreibweise für eine Kombination aus den Zuständen BB und DD.


Kurzer Ausflug in die interne Darstellung in php:
  • Während jeder Rechner - jedenfalls bisher - intern ausschließlich bitweise, also mit Binärzahlen arbeitet, bietet php selbst gar keinen Variablentyp, der Binärzahlen darstellt. Allerdings ist das auch nicht nötig. Für eine Darstellung wie eben bietet sich der Stringtyp an, rechnen tut php jedoch mit integer Zahlen, auf die man trotzdem Bit-Operatoren anwenden kann. Der Hintergrund ist rein mathematisch: Eine Binärzahl ist lediglich in einem anderen Zahlensystem definiert, rechnen läßt sich ebenso gut mit einer Repräsentation derselben Zahl im Zehner-(Dezimal-)system. Wenn hier also von Binärzahlen die Rede ist, so nutzt php doch einen Integer als Variablentyp.


1. Verwendung als Flag (Zustandsangabe)

Nehmen wir an, unsere Zustände AA bis DD sollen einer Funktion bestimmte Verhaltensweisen signalisieren.
Wir definieren uns zunächst, wie oben bereits beschrieben unsere Binärwerte als Konstante.

PHP-Code:
<?
define 
('AA' 1);
define ('BB' 2);
define ('CC' 4);
define ('DD' 8);
Dann kommt unsere Funktion. Sie erfüllt in diesem Beispiel keinen anderen Zweck, als auf die gesetzten Flags zu reagieren:

PHP-Code:
<?
function test ($flags)
  {
  if ((
AA $flags) == AA) echo 'AA';
  if ((
BB $flags) == BB) echo 'BB';
  if ((
CC $flags) == CC) echo 'CC';
  if ((
DD $flags) == DD) echo 'DD';
  }
Wir rufen die Funktion mit test (AA | CC); auf und erhalten folgende Ausgabe:

Code:
AACC
Wie funktionierts? Bei der Übergabe werden die durch AA und CC repräsentierten Werte binär ODER-Verknüpft:

Code:
     0001 (AA)
ODER 0100 (CC)
     ----
     0101
Die ODER-Verknüpfung setzt dabei an jede Dualstelle eine 1, an der in einem der beiden Werte eine 1 steht. Das Resultat binär 0101 wird an die Funktion übergeben. Würden wir in test die Variable $flag ausgeben, würden wir aus o.g. Gründen nur die Dezimaldarstellung der Zahl sehen, konkret die 5.
Innerhalb der Funktion gilt es nun, die Flags wieder voneinander zu trennen. Wir wollen dies mit einem weiteren Bit-Operator, dem UND tun. UND tut genau das Gegenteil von ODER: es setzt jede Dualstelle auf 0, an der in mindestens einem der Operanden auch eine 0 steht.
Da die Konstanten global und damit auch in der Funktion verfügbar sind, prüfen wir nun alle 4 Flags auf Gesetztsein des entsprechenden Bits, in dem wir sie mit dem Inhalt von $flags UND-verknüpfen. Exemplarisch für AA und BB:

Code:
    0101 ($flags)
UND 0001 (AA)
    ----
    0001

    0101 ($flags)
UND 0010 (BB)
    ----
    0000
Wie wir sehen, ergibt sich für gesetzte Flags genau der jeweils in der Konstante definierte Binärwert, für nicht gesetzte Flags der Binärwert 0.
In unserer Funktion werden alle 4 Zustände geprüft und bei Übereinstimmung mit der Konstante der gesetzte Zustand durch Ausgabe des Konstantennamens signalisiert. Bei einer 'echten' Funktion könnten jetzt hier bestimmte Fälle abgearbeitet werden, wobei meist weitere Parametervariablen verarbeitet werden würden.


2. Verwendung gegenteiliger Flags

php Funktionen wie bspw. preg_match_all() verwenden auch durchaus Flags, die miteinander kombiniert gegenteilige Bedeutungen haben. Da Binärstellen prinzipbedingt nur zwei Zustände aufnehmen können, werden diese Zustände zunächst genauso angegeben wie im Vorgängerbeispiel, in der Funktion muß dann die logische Auswertung erfolgen.

PHP-Code:
<?
function test2 ($flags)
  {
  
// bevorzugtes Flag
  
if ((AA $flags) == AA
    {
    
$flags $flags & ~BB;
    echo 
'AA';
    }
  if ((
BB $flags) == BB) echo 'BB';
  if ((
CC $flags) == CC) echo 'CC';
  if ((
DD $flags) == DD) echo 'DD';
  }
In dieser Funktion schließt die Angabe von AA den Zustand BB aus. Wie vorher wird dazu geprüft, ob Zustand AA gesetzt ist. Wenn nicht, geht alles seinen gewohnten Gang. Falls doch, muß der Zustand BB aus $flags entfernt werden, um die nachfolgende Abarbeitung für BB zu unterbinden. Wieder hilft uns eine logische Operation - $flags wird mit dem inversen Wert von BB UND-verknüpft. Die für BB repräsentative Dualstelle 1 wird dabei zur 0 und löscht die entsprechende Stelle aus $flags aus, alle anderen Stellen werden 1 und stellen so sicher, dass die weiteren Dualstellen in $flags unbeeinflusst bleiben:

Code:
    0010 (BB)
NOT      (~)
    ----
    1101

    1011 ($flags)
    1101 (~ BB)
    ----
    1001
Voila! Aus unserer usprünglichen Zustandsangabe AA | BB | DD wurde BB während der Abarbeitung von AA entfernt. Übrig bleiben die dual definierten Zustände AA und DD.

Der Aufruf test2 (AA | BB | DD); gibt also zurück:

Code:
AADD
3. Verwendung des höchstwertigen Flag

Zerglings Ausgangsfrage bezog sich auf die Aufgabenstellung, eine Art Maximum der verwendeten Flags zu bestimmen, genauer gesagt, den größten innerhalb von $flags verwendeten Exponenten. Mir ist keine Möglichkeit mit Bit-Operatoren dafür bekannt. Mathematisch ausgedrückt gilt es, den 2er Logarithmus des Wertes in $flags zu bestimmen. Der ganzzahlige Teil des Ergebnisses ist unser Wert.
php bietet hier eine einfachere Variante. Wir verwandeln mittels decbin() den Wert in $flags seine Stringrepräsentation, also in eine Folge von Null- und Eins-Zeichen. Von rechts beginnend steht jede Dualstelle für einen Exponenten, die erste für 2 hoch 0, die zweite für 2 hoch 1 usw. Da php intern nicht mit führenden Nullen arbeitet (wie gesagt, eigentlich ja nicht einmal mit Binärzahlen) und wir die am weitesten links stehende 1 suchen, kann das Ergebnis direkt aus der Länge der Stringrepräsentation unserer Binärzahl bestimmt werden. Wir ziehen noch 1 ab, da das erste Zeichen für 2 hoch 0 steht.
Für unsere Signalfunktion (also um unserer Beispielfunktion hier irgendeinen Nutzen zu geben) verwenden wir den Exponenten, den wir erhalten haben, um mit pow() wieder eine Binärzahl zu erzeugen. Die Ausgabe erfolgt in einem Switch, da ja nur das höchstwertige gesetzte Flag gesucht war.

PHP-Code:
<?
function test3 ($flags)
  {
  switch (
pow (strlen (decbin ($flags)) - 1))
    {
    case  
AA:
      echo 
'AA';
      break;
  
    case  
BB
      echo 
'BB';
      break;
  
    case  
CC
      echo 
'CC';
      break;
  
    case  
DD
      echo 
'DD';
      break;
    }
  }
4. Eine große oder unbekannte Anzahl von Flags

Zuletzt ein etwas konstruiertes Beispiel, das mit dem Shift Operator arbeitet.
Nehmen wir an, wir wollen die übergebenen Flag-Bits nicht individuell prüfen und verarbeiten, sondern per Schleife (z.B. weil wir nicht wissen, welche numerischen Flags vorkommen können). Es wird also nötig, Bit für Bit, von 2 hoch 0 bis 2 hoch n auszulesen. Stellt man sich einen solchen Bitwert vor, wäre die naheliegendste Variante, diesen als String zu betrachten, per Schleife zeichenweise zu durchlaufen und den aktuellen numerischen Schlüssel mit der geschwungenen Klammer Syntax auszulesen. Das ist in php auch durchaus legitim, da es sich um eine schwach typisierte Sprache handelt und die Umwandlung der verschiedenen Typen im Allgemeinen automatisch erfolgt.
Trotzdem möchte ich hier auch die Arbeit mit Bit-Operatoren vorstellen. Als Beispiel sollen hier einfach die Binärwerte der gesetzten Zustände ausgegeben werden. Stellt man sich jetzt 40 statt der bisher verwendeten 4 Flags vor, sieht man, dass eine Lösung wie in der ersten Funktion unglaublich viel redundaten Code erzeugen würde. Stattdessen nutzen wir eine Schleife:

PHP-Code:
<?
function test4 ($flags)
  {
  
$iMax 10;
  for (
$iCnt $iMax$iCnt $iCnt--)
    {
    if (
!= ($flags & (<< ($iCnt 1)))) echo pow ($iCnt 1);
    }
  }

test4 (AA CC DD);
Ausgabe:
Code:
841
Der Clou an dieser Funktion ist das Bit-Shifting: mit dem << Operator wird eine Binärzahl erzeugt, die dann, ähnlich wie in der ersten Funktion mit $flags UND-verknüpft wird. Der Shift-Operator füllt die Ausgangszahl (1, binär 1) rechts mit weiteren Nullen auf, in Folge dessen wird $flags nacheinander mit 10000000000 , 1000000000 , 100000000 ... 1 UND-verknüpft und auf Vorhandensein eines Ergebnisses größer 0 geprüft. Bei Erfolg war das aktuelle Flag gesetzt, was durch die Ausgabe des Expontenten signalisiert wurde.
Übrigens: Statt $iMax fest zu definieren, könnte auch hier wie oben die Anzahl der maximalen Dualstellen von $flags ermittelt werden.


Auch wenn's zuletzt dann doch noch etwas knifflig wurde, könnt Ihr hoffentlich den einen oder anderen Punkt umsetzen, um eure Funktionen um eine paar Flag-gesteuerte Erweiterungen zu bereichern. Sinnvollerweise sollte der $flags Parameter immer mit 0 oder einem Defaultwert vorbelegt sein.

Viel Spaß beim Ausprobieren, Anmerkungen und Berichtigungen sind willkommen.
--n
nikosch ist offline   Mit Zitat antworten
Sponsor Mitteilung
PHP Code Flüsterer

Registriert seit: 21.08.2005
Beiträge: 4682
PHP-Kenntnisse:
Fortgeschritten

Alt 18.07.2007, 21:48  
Erfahrener Benutzer
 
Registriert seit: 21.05.2008
Beiträge: 9.937
Zergling-new wird schon bald berühmt werden
Standard

Hast du schön gemacht

Bekanntestes Beispiel hierfür sind ja die Error-Reporting-Flags in PHP, hier ein Auszug aus einer php.ini:
Code:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Error handling and logging ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; error_reporting is a bit-field.  Or each number up to get desired error
; reporting level
;
; Examples:
;
;   - Show all errors, except for notices and coding standards warnings
;
;error_reporting = E_ALL & ~E_NOTICE
;
;   - Show all errors, except for notices
;
;error_reporting = E_ALL & ~E_NOTICE | E_STRICT
;
;   - Show only errors
;
;error_reporting = E_COMPILE_ERROR|E_ERROR|E_CORE_ERROR
;
error_reporting  =  E_ALL
http://de3.php.net/manual/de/functio...-reporting.php
Zitat:
Tabelle 77. error_reporting() Konstanten und Bitwerte
Bitwert Konstante
1 E_ERROR
2 E_WARNING
4 E_PARSE
8 E_NOTICE
16 E_CORE_ERROR
32 E_CORE_WARNING
64 E_COMPILE_ERROR
128 E_COMPILE_WARNING
256 E_USER_ERROR
512 E_USER_WARNING
1024 E_USER_NOTICE
6143 E_ALL
2048 E_STRICT
Gute Frage allerdings, warum E_ALL jetzt auf 6143 steht, die Summe der restlichen Flags + 1 scheint es ja nicht zu sein.

Ist halt wirklich ne schöne Geschichte mit den Flags, weil man TRUE/FALSE Optionseinstellungen gesammelt einfach in eine Variable packen kann.

Überlege man sich mal, ich müsste - bezogen auf den von nikosch verlinkten Thread von mir - für eine CSV-Spalte speichern, ob darin VARCHAR, INTEGER, DATE, etc. Werte gefunden hätte, ohne dabei auf eine Bitmaske zurückzugreifen. Das würde schnell sehr unübersichtlich werden.
Zergling-new ist offline   Mit Zitat antworten
Alt 18.07.2007, 22:09  
moderatives Dielektrikum
 
Benutzerbild von nikosch
 
Registriert seit: 21.05.2008
Beiträge: 35.994
PHP-Kenntnisse:
Fortgeschritten
nikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunft
Standard

Gute Frage, vor allem weil 6143 binär 1011111111111 ist. Wozu die Null frag ich mich da. Wohl um E_STRICT explizit auszuschließen. 2^0 bis 2^10 sind ja abgedeckt. Und auch 4096 ist bereits definiert - als E_RECOVERABLE_ERROR:
Zitat:
Catchable fatal error. It indicates that a probably dangerous error occured, but did not leave the Engine in an unstable state. If the error is not caught by a user defined handle (see also set_error_handler()), the application aborts as it was an E_ERROR.
Dann stimmts ja wieder! Abzüglich E_STRICT natürlich.
E_ALL ist je nach Version aber auch als 8191 bzw. 2047 definiert. 8191 übrigens dann ohne die Lücke für E_STRICT.
nikosch ist offline   Mit Zitat antworten
Alt 18.07.2007, 22:25  
Erfahrener Benutzer
 
Registriert seit: 21.05.2008
Beiträge: 9.937
Zergling-new wird schon bald berühmt werden
Standard

Zitat:
Gute Frage, vor allem weil 6143 binär 1011111111111 ist. Wozu die Null frag ich mich da. Wohl um E_STRICT explizit auszuschließen.
Stimmt, E_STRICT is ja nich mit drin.
Zergling-new ist offline   Mit Zitat antworten
Antwort


Themen-Optionen
Thema bewerten
Thema bewerten:

Forumregeln
Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are an
Gehe zu

Ähnliche Themen
Thema Autor Forum Antworten Letzter Beitrag
mit jQuery grosse Formulare verarbeiten phpbeginner HTML, Usability und Barrierefreiheit 5 13.06.2008 22:58
Funktions Problem mit Array andrew22 PHP Tipps 2007 11 03.07.2007 17:30
C64 .sid sounds verarbeiten notyyy PHP Tipps 2007 2 22.03.2007 23:14
einlesen und verarbeiten PHP Tipps 2006 4 28.11.2006 16:04
Abfrageergebnis besser verarbeiten HalliGalli PHP Tipps 2006 2 17.05.2006 10:11
Mehrere inserts auf einmal verarbeiten pixelcut PHP Tipps 2005-2 15 17.08.2005 19:15
datei lesen string verarbeiten und wieder abspeichern PHP Tipps 2005-2 17 22.06.2005 16:02
post verarbeiten notyyy PHP Tipps 2005-2 3 11.06.2005 12:26
Phpmyadmins SQL Dump Auslesen und verarbeiten PHP Tipps 2004 3 23.10.2004 16:51
Riesige Datei verarbeiten Ohrwurm83 PHP Tipps 2004 10 21.10.2004 11:41
Counterdaten verarbeiten juhuwoorps PHP Tipps 2004 4 29.08.2004 02:09
Daten von HTML-Form mit POST verarbeiten PHP Tipps 2004 1 13.08.2004 21:35
Variable aus Eingabefeld in mein PHP-Skript verarbeiten PHP Tipps 2004 5 26.07.2004 09:50
Daten aus Java-Script in PHP verarbeiten PHP Tipps 2004 33 22.07.2004 09:41
array stückweise in for-schleife verarbeiten PHP Tipps 2004 4 03.06.2004 13:51

Besucher kamen über folgende Suchanfragen bei Google auf diese Seite
php flags, php flag, flags php, flag php, php flags kombinieren, php flags setzen, php flag setzen, php mehrere flags, php $flag, bit shifting switches php, php funktion flag, php bitoperationen flag, php binärzahl bitweise vergleichen, php function flags, flags rechnen, php or flag, php flagg, binärsystem flags, php was sind flags, flags binär berechnen

Alle Zeitangaben in WEZ +2. Es ist jetzt 02:16 Uhr.




Powered by vBulletin® Version 3.7.2 (Deutsch)
Copyright ©2000 - 2012, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.2.0
Aprilia-Forum, Aquaristik-Forum, Liebeskummer-Forum, Zierfisch-Forum, Geizkragen-Forum

Creative Commons License
Dieser Inhalt ist unter einer Creative Commons-Lizenz lizenziert.