Gelegentlich soll eine Frage nicht alle Items anzeigen, sondern nur solche, die in einer anderen Frage vorher ausgewählt wurden. Und eventuell soll die Anzahl der Items auch noch beschränkt werden. Dieses Kapitel beschreibt sogenannte Arrays, mit denen man mächtige Filter für solche Anwendungsfälle erstellen kann.
Arrays sind in PHP ein ungemein praktisches Werkzeug, daher genießen diese Konstrukte hier eine ausführliche Einführung. Konkreten Lösungen für verschiedene Anwendungsfälle finden Sie weiter unten (Aufgabenstellung 1).
Bei einem Array handelt es sich um eine Liste von Werten. Der folgende PHP-Code erzeugt ein einfaches Array mit drei Listeneinträgen (in diesem Fall Texte): „eins“, „zwei“ und „drei“. Das Array wird anschließend in der Variable $a abgelegt.
// Ein Array anlegen $a = array('eins', 'zwei', 'drei');
Die damit erzeugte Liste sieht aus wie folgt. Jeder Eintrag in der Liste erhält eine Nummer (den sogenannten Index oder Schlüssel), der i.d.R. bei 0 beginnt. Die Länge dieser Liste ist 3.
Wert | eins | zwei | drei |
---|---|---|---|
Index | 0 | 1 | 2 |
Mit eckigen Klammern ([]
)) kann man nun auf die einzelnen Einträge im Array zugreifen. Zwischen die klammern wird einfach der Index geschrieben. Der Befehl count()
verrät etwas über die Länge des Arrays.
// Mit Arrays arbeiten $a = array('eins', 'zwei', 'drei'); html('<p>Länge des Arrays: '.count($a).'</p>'); html('<p>Eintrag mit Index 0: '.$a[0].'</p>'); html('<p>Eintrag mit Index 2: '.$a[2].'</p>');
Der Beispiel-Code erzeugt folgende Ausgabe im Fragebogen:
Länge des Arrays: 3 Eintrag mit Index 0: eins Eintrag mit Index 2: drei
Besonders praktisch in PHP ist die Möglichkeit, einfach ein Element an das Array anzuhängen. Dazu schreibt man leere eckige Klammern hinter die Array-Variable und dann nach einem Gleichheitszeichen was angefügt werden soll:
// Arrays erweitern $a = array('eins', 'zwei', 'drei'); $a[] = 'angehängt'; $a[] = 'noch eins';
Dieses Array hätte nun eine Länge von 5 Elementen und sieht wie folgt aus:
Wert | eins | zwei | drei | angehängt | noch eins |
---|---|---|---|---|---|
Index | 0 | 1 | 2 | 3 | 4 |
Besonders hilfreich klingt das zunächst noch nicht. Aber Arrays lassen sich optimal mit Schleifen kombinieren. Im folgenden Beispiel werden die Werte des obigen Arrays angeschrieben - beachten Sie, dass Sie 5 Werte mit einem einzigen Befehl in der Schleife verarbeiten können.
// Arrays und Schleifen $a = array('eins', 'zwei', 'drei'); $a[] = 'angehängt'; $a[] = 'noch eins'; for ($i=0; $i<count($a); $i++) { html('<p>Element '.$i.' = '.$a[$i].'</p>'); }
Der PHP-Code erzeugt folgende Ausgabe im Fragebogen:
Element 0 = eins Element 1 = zwei Element 2 = drei Element 3 = angehängt Element 4 = noch eins
Besonders hilfreich sind die dargestellten Beispiele aber noch immer nicht. Bevor es um die konkrete Anwendung geht, seien aber noch einige Funktionen vorgestellt, die in oFb besonders häufig gebraucht werden.
Die Funktion shuffle(&array Array)
mischt ein Array. Das ist nützlich, wenn man aus einer Liste zufällig einzelne Einträge heraussuchen möchte.
$a = array('eins', 'zwei', 'drei', 'vier', 'fünf'); shuffle($a); html('<p>Zwei zufällig ausgesuchte Werte:<br>'. $a[0].' und '.$a[1]. '</p>');
Der Code erzeugt z.B. folgende Ausgabe im Fragebogen:
Zwei zufällig ausgesuchte Werte: fünf und drei
Im Gegenzug sortiert der Befehl sort(&array Array)
das Array. Wenn man (wie im Beispiel) Texte verwendet, dann werden diese alphabetisch sortiert:
$a = array('eins', 'zwei', 'drei', 'vier', 'fünf'); sort($a); for ($i=0; $i<count($a); $i++) { html('<p>Eintrag '.$i.' = '.$a[$i].'</p>'); }
Dieser PHP-Code erzeugt folgende Ausgabe im Fragebogen, die Werte wurden hier alphabetisch sortiert:
Eintrag 0 = drei Eintrag 1 = eins Eintrag 2 = fünf Eintrag 3 = vier Eintrag 4 = zwei
Der Befehl implode(string Trennzeichen, array Array)
verbindet alle Einträge des Arrays zu einem Text. Man kann als ersten Parameter angeben, durch welches Zeichen die Einträge getrennt werden sollen:
$a = array('eins', 'zwei', 'drei', 'vier', 'fünf'); html('<p>Inhalt vorher: '.implode('|', $a).'</p>'); shuffle($a); html('<p>Inhalt nachher: '.implode('|', $a).'</p>'); html('<p>Inhalt mit Komma: '.implode(', ', $a).'</p>');
Der Code erzeugt z.B. folgende Ausgabe im Fragebogen:
Inhalt vorher: eins|zwei|drei|vier|fünf Inhalt nachher: vier|zwei|eins|drei|fünf Inhalt mit Komma: vier, zwei, eins, drei, fünf
Der Befehl in_array(mixed Element, array Array)
überprüft, ob ein Element in einem Array vorhanden ist. Das ist vor allem dann nützlich, wenn man unterschiedliche Fragen stellt in Abhängigkeit von Array-Elementen.
$a = array(1,2,7,8); // Liste mit Zahlen (das könnten ebenso die angekreuzten Items sein) if (in_array(2,$a)) { question('AB01'); } if (in_array(3,$a)) { question('AB02'); }
Sie möchten die Items anfragen, die in einer vorhergehenden Frage angekreuzt wurden – keinesfalls aber die Items 4 und 5? Dann können Sie mit array_diff()
einfach die Items 4 und 5 aus der Liste entfernen.
// Ausgewählte Items ermitteln $auswahl = getItems('AB01', 'min', 2'); // Die Items 4 und 5 aus der Liste entfernen, falls vorhanden $never = array(4, 5); $items = array_diff($auswahl, $never); // Die Folgefrage stellen question('AB02', $items);
Ähnlich hilfreich sind array_merge()
(Vereinigungsmenge) und array_intersect()
(Schnittmenge).
Es gibt noch eine ganze Reihe weiterer Befehle für Arrays. Eine vollständige Liste finden Sie im offiziellen PHP Manual: Array-Funktionen.
Wenn Sie das Zusammenspiel von Arrays, Schleifen und Filtern im Fragebogen detailliert verstehen möchten, nehmen Sie sich bei der folgenden Aufgabenstellung 1 eine Minute und lesen Sie auch den langen Weg.
Als Beispiel für dieses Kapitel wird die folgenden Fragen (TF04) verwendet:
In folgender Frage (TF05) sollen nur die Medien zur Auswahl stehen, die der Befragte mindestens einmal im Monat nutzt. Damit dieselben Items mit derselben Kennung enthalten sind, wurde die obigen Frage einfach kopiert (Frage duplizieren oben in der Frage) und anschließend in der Kopie Frage-Typ und -Texte geändert.
Ziel ist es nun, dass die zweite Frage nur die Medien (Items) zu Auswahl zeigt, die in der ersten Frage eine Bewertung von mindestens 2 erhalten haben.
Die Funktion getItems()
erstellt Ihnen eine Liste (Array) jener Items, die mindestens (min) einmal im Monat genutzt werden (Ausprägung 2). Diese Liste übergeben Sie einfach der Funktion question() – aber natürlich nur dann, wenn sie mindestens ein Element enthält.
Wenn Sie die Frage TF04 auf Seite 1 gestellt haben, können Sie folgenden Code frühestens auf Seite 2 plazieren:
$medien = getItems('TF04', 'min', 2); if (count($medien) > 0) { question('TF05', $medien); }
Die weitere Anleitung beschreibt, wie Sie mit Arrays im Detail arbeiten. Dies ist vor allem dann interessant, wenn getItems()
einmal nicht weiterhilft.
Die Funktion getItems()
erstellt ein Array – das kann man auch zu Fuß erledigen. Man muss ja nur ein Array erstellen, in dem alle Item-Kennungen stehen, die in der zweiten Frage auftauchen sollen. Das funktioniert wie folgt.
$itemliste = array(); // Eine leere Liste erstellen $anzahl_items = 6; // 6 Items überprüfen $frage = 'TF04'; for ($i=1; $i<=$anzahl_items; $i++) { // Durchzählen von 1 bis 6 $kennung = $frage.'_'.$i; // Ergibt z.B. TF_04_1 // Hat das Item einen Wert von mindestens 2? if (value($kennung) >= 2) { $itemliste[] = $i; } } // Nur zur Information html( '<p>'. count($itemliste).' relevante Items: '. implode(', ', $itemliste). '</p>' ); // Weiter zur nächsten Seite, wenn nichts genutzt if (count($itemliste) == 0) { goToPage('next'); } // Zweite Frage mit diesen Items stellen question('TF05', $itemliste);
Bei der Programmierung solcher Filter sollte man nicht vergessen, dass vielleicht gar kein Item ausgewählt wird. Deshalb wird der Teilnehmer im obigen Beispiel direkt zur nächsten Seite weitergeleitet, wenn er kein Medium wenigstens einmal im Monat nutzt.
Für das obige Beispiel könnte man auf Seite 1 folgende Angaben machen:
Fernsehen, Internet und der Telegraph erfüllen also nicht die Voraussetzung, dass sie mindestens einmal im Monat genutzt werden. Dann würde Seite 2 so aussehen:
Nun sollen Polaritätenprofile für die einzelnen Medien erfragt werden. Allerdings nur für solche Medien, die der Befragte mindestens einmal pro Monat nutzt. Außerdem sollen maximal 2 Polprofile abgefragt werden. Falls der Befragte mehr Medien nutzt, sollen zufällig zwei ausgewählt werden.
Grundlage sind 6 gleichartige Fragen (TF06 bis TF11), in denen lediglich der Fragetext variiert. In der ersten Frage steht dort „Tageszeitung“, in der nächsten „Radio“ u.s.w. Die Frage wird einmal erstellt, anschließend fünf mal kopiert und abschließend Bezeichnung und Fragetext geändert.
Wie man eine Liste der genutzten Medien erstellt, ist oben bereits ausführlich beschrieben.
// Variante A: Bequem $itemliste = getItems('TF04', 'min', 2); // Liste der relevanten Items
// Variante B: Zu Fuß $itemliste = array(); // Eine leere Liste erstellen $anzahl_items = 6; // 6 Items überprüfen $frage = 'TF04'; for ($i=1; $i<=$anzahl_items; $i++) { $kennung = $frage.'_'.$i; // Ergibt z.B. TF_04_1 if (value($kennung) >= 2) { $itemliste[] = $i; } }
Falls die Liste mehr als zwei Einträge hat, müssen 2 Einträge zufällig ausgewählt werden. Um das zu erreichen könnte man die Liste mischen und anschließend die beiden ersten Einträge in ein neues Array kopieren:
// ... // Fortsetzung Variante I if (count($itemliste) > 2) { shuffle($itemliste); $neue_liste = array(); $neue_liste[] = $itemliste[0]; // Kopiert Element 0 $neue_liste[] = $itemliste[1]; // Kopiert Element 1 } else { $neue_liste = $itemliste; // Sonst die Liste wie gehabt verwenden }
Man kann sich das Umkopieren in eine neue Liste auch sparen, die Liste einfach nur mischen und nachher nur die ersten beiden Einträge verwenden.
// ... // Fortsetzung Variante II shuffle($itemliste);
Jetzt müssen nur noch die entsprechenden Fragen gestellt werden. Auch das funktioniert wieder am schnellsten mit Hilfe eines Arrays. Man hat die Möglichkeit, in einem Array anzugeben, welcher Eintrag welchen Index erhält. Dazu wird ein Array wie folgt erstellt: Es wird jeweils der Index angegeben, dann ein Gleichheitszeichen und ein größer-als-Zeichen (⇒
) und dann erst der eigentliche Eintrag. Das Ergebnis wird dann als assoziatives Array bezeichnet, während die „normalen“ Arrays indiziert sind.
// ... // Fortsetzung $fragen = array( 1 => 'TF06', 2 => 'TF07', 3 => 'TF08', 4 => 'TF09', 5 => 'TF10', 6 => 'TF11' );
In diesem Array beginnen die Indizes nun nicht mit 0, sondern mit 1. Das Array sieht aus wie folgt:
Wert | TF_06 | TF_07 | TF_08 | TF_09 | TF_10 | TF_11 |
---|---|---|---|---|---|---|
Index | 1 | 2 | 3 | 4 | 5 | 6 |
Mit $fragen[2]
erhält man jetzt die Kennung der Frage, die zu Item 2 („Radio“) gehört, nämlich 'TF07'. So kann man nun ganz einfach die Fragen zu den genutzten Medien stellen:
// ... // Fortsetzung $anzahl = count($itemliste); // So viele Elemente können erfragt werden if ($anzahl > 2) { $anzahl = 2; // Maximal zwei Polprofile abfragen } if ($anzahl == 0) { goToPage('next'); // Nichts genutzt? Dann gleich weiter! } for ($i=0; $i<$anzahl; $i++) { $item_kenn = $itemliste[$i]; // Einer der genutzten Dienste (1 bis 6) $frage_kenn = $fragen[$item_kenn]; question($frage_kenn); // Frage stellen }
Die Schleife stellt nur maximal $anzahl
Fragen. Vorher wird begrenzt, dass $anzahl
immer maximal 2 sein kann. Gleichzeitig kann die Anzahl nie größer sein als die Anzahl der genutzten Medien (also der Listenlänge).
Der vollständige Code für dieses Beispiel sieht so aus:
$itemliste = getItems('TF04', 'min', 2); // Relevante Items ermitteln shuffle($itemliste); // Liste mischen // Fragen zu den Items definieren $fragen = array( 1 => 'TF06', 2 => 'TF07', 3 => 'TF08', 4 => 'TF09', 5 => 'TF10', 6 => 'TF11' ); $anzahl = count($itemliste); // So viele Elemente können erfragt werden if ($anzahl > 2) { $anzahl = 2; // Maximal zwei Polprofile abfragen } if ($anzahl == 0) { goToPage('next'); // Nichts genutzt? Dann gleich weiter! } for ($i=0; $i<$anzahl; $i++) { $item_kenn = $itemliste[$i]; // Einer der genutzten Dienste (1 bis 6) $frage_kenn = $fragen[$item_kenn]; // Die entspr. Frage question($frage_kenn); // Frage stellen }
Im Fragebogen könnte das dann so aussehen (wobei die aktuelle oFb-Version dafür sorgt, dass alles sauber übereinander steht):
Seite 2 zeigt zufällig die Fragen für Tageszeitung, Radio oder Videokonferenz. Beachten Sie, dass die Reihenfolge der Fragen eine andere sein kann als die der Items (oben).
Manchmal wird die Nutzung in unterschiedlichen Fragen erhoben. Zum Beispiel fragt (Auswahl-)Frage NU01 nach der Nutzung von Weblogs, NU02 nach der Nutzung von Podcasts und NU03 nach Wikis.
Nun sollen in der Frage TF13 immer die Items 1 bis 3 gefragt werden. Die Items 4, 5 und 6 sollen nur gefragt werden, wenn der entsprechende Dienst genutzt wird. Das ist nach dieser Anleitung freilich überhaupt kein Problem mehr:
// Auf Seite 1 werden zunächst die drei Fragen gestellt question('NU01'); // Nutzen Sie Weblogs? (1=nein, 2=ja) question('NU02'); // Nutzen Sie Podcasts? (1=nein, 2=ja) question('NU03'); // Verwendung von Wikis - Item 2 ist Nutzung // Werte: 1=nie 2=selten 3=häufig
// Auf Seite 2 wird eine Item-Liste erzeugt und abgefragt $items = array(1,2,3); // Items 1-3 werden immer gefragt if (value('NU01') == 2) { $items[] = 4; // Weblogs genutzt => Item 4 } if (value('NU02') == 2) { $items[] = 5; // Podcasts genutzt => Item 5 } if (value('NU03_02') >= 2) { $items[] = 6; // Wikis min. selten => Item 6 } // Zu guter Letzte die Frage stellen question('TF13', $items);
Fast schon trivial mutet der Fall an, dass die ausgewählten Items aus einer anderen Frage übernommen werden sollen – und zusätzlich soll noch eine Option „Sonstiges“ angezeigt werden.
Dazu legt man in der zweiten Fragen (z.B. TF05) nach den Items aus der Filterfrage (TF04) noch ein weiteres Item „Sonstiges“ an. Das folgende Beispiel geht davon aus, dass dieses Item die Kennung 13 hat. Nun ermittelt man die ausgewählten Items und hängt an die Liste noch die Nummer 13 an. Dafür wird einfach eine leere eckige Klammern ([]
) verwendet – alternativ könnte man auch den PHP-Befehl array_push()
dazu verwenden.
$auswahl = getItems('TF04'); // Ausgewählte Items ermitteln $auswahl[] = 13; // Die Zahl 13 an die Liste anhängen question('AF05', $auswahl); // Die Folgefrage inkl. Item 13 anzeigen
Damit dieser Filter funktioniert, muss man die Kennung des zusätzlichen Items angeben. Natürlich könnte man auch zunächst ermitteln, welche Items in der zweiten, nicht aber in der ersten Frage vorhanden sind. Die Funktion array_diff()
liefert eine Liste genau solcher Listenelemente und mit der Funktion array_merge()
lassen sich die Listen anschließend kombinieren.
// Zusätzliche Items ermitteln $items1 = getItems('TF04', 'all'); // Alle Items der Frage 1 auflisten $items2 = getItems('TF05', 'all'); // Alle Items der Frage 2 auflisten $added = array_diff($items2, $items1); // Items, die in Frage 2 vorkommen, nicht aber in Frage 1 $auswahl = getItems('TF04'); // Ausgewählte Items ermitteln $auswahl = array_merge($auswahl, $added); // Zusätzliche Items an die Liste anhängen question('AF05', $auswahl); // Die Folgefrage inkl. zusätzlicher Items anzeigen