Vinzenz Mai: interner zähler addiert für $i++ zwei?

Beitrag lesen

Hallo David,

Mhh, da lass ich mich gerne belehren. Das Konstrukt unerbricht den html Tag, weil im Falle einer falschen Usereingabe die bereits eingegebenen Daten wieder ausgegeben werden sollen (Affenformular).

erstens empfehle ich die Verwendung einer kleinen Funktion für diese Aufgabe.

Im Falle einer select-Box bedeutet das, dass der Option-Tag die Option 'selected' benötigt, falls bereits ein Wert gesetzt war. Wenn Dir etwas elegentares einfällt, also dazu im Tag die if-Schleife zu setzen, lass es mich bitte wissen, damit ich meinen Stil auch verbessern kann und nicht nur weiss, dass er 'miserabel' und 'grottig' ist. Hier nochmal das entsprechende Code Schnippsel:

Zweitens ist es besserer Stil, in dieser Funktion getreu dem EVA-Prinzip _keine_ Ausgabe vornehmen, sondern nur den fertigen HTML-Code im Rückgabewert zur Verfügung stellen.

<select name="from_day">
<option ";
if ($_REQUEST["from_day"]=="0") print " selected ";
print "value="0">--</option><option ";

for ($i=1; $i<=31; $i++)
{
if ($_REQUEST["from_day"]==$i) print " selected ";
  print "value="" . $i . "">" . $i ."</option>";
  if ($i<=30) print "<option ";
}
print "</select>

  
Zuerst eine kleine Aufgabenbeschreibung  
  
~~~php
  
/**  
 *   Gibt eine Zeichenkette mit einem SELECT-Element aus.  
 *   Das erste Option-Element hat den Wert 0 und die Anzeige "---".  
 *   Die anderen Option-Elemente haben gleichen Wert und gleiche Anzeige.  
 *   Die Wertemenge geht von 1 bis 31  
 *   Wenn ein Wert zwischen 1 und 31 ausgewählt ist, dann wird  
 *   dieser Wert über das Attribut selected="selected" vorausgewählt  
 *   Ist der Wert nicht in diesem Intervall enthalten, so wird  
 *   wird das erste Option-Element vorausgewählt  
 */  

Dir sollte als erstes auffallen, dass meine Aufgabenbeschreibung _nicht_ die Gleichheit des Wertes mit "0" überprüft. Damit soll auch bei (absichtlich) fehlerhafter Wertübergabe eine sinnvolle Ausgabe erzeugt werden.

  
function create_numeric_select_element($myvalue = 0) {  
    // Baue Deine Ausgabe in der Variablen $output zusammen  
    $output = '<select name="from_day">' . "\n";  
  
    // Baue nun die Option-Zeichenkette zusammen  
    $options = '';  
    // Die vorausgewählte Option benötigt folgendes zusätzliches Attribut  
    $selected = ' selected="selected"';  
    // Bisher wurde noch kein Element vorausgewählt  
    $is_selected = false;  
  
    // Durchlaufe die sinnvollen Tageswerte.  
    // Baue je Durchlauf ein komplettes option-Element zusammen und hänge  
    // es an die dafür vorgesehene Zeichenkettenvariable an.  
    for ($i = 1, $i <= 31, $i++) {  
        // Baue die Zeichenkette für jeden Wert Schritt für Schritt zusammen  
        $options .= '<option value="';  // jede Option fängt so an  
        $options .= $i;                 // jede Option braucht diesen Wert  
        $options .= '"';                // dieser muss richtig beendet werden  
        if ($i === $myvalue) {          // Wenn wir den übergebenen Wert haben  
            $options .= $selected;      // muss dieser vorausgewählt werden  
            $is_selected = true;        // setze das Flag  
        }  
        $options .= ">$i</option>\n"    // Schreibe den angezeigten Wert und  
                                        // beende die Option  
    }  
  
    // Nun ist noch das erste option-Element vorne anzufügen.  
    // Wenn noch kein Element vorausgewählt wurde,  
    //     dann ist das erste auszuwählen,  
    // Sonst  
    //     ist bereits eines vorausgewählt,  
    //     und das erste wird deswegen nicht vorausgewählt.  
    if ($is_selected == false) {        // Noch kein Element vorausgewählt, also  
                                        // muss der erste vorausgewählt sein  
        $options = '<option value="0" selected="selected">---</option>'  
                   . "\n" . $options;  
    }  
    else {                              // Ein Wert zwischen 1 und 31 ist bereits  
                                        // vorausgewählt, es kann nur eine geben :-)  
        $options = 'option value='0">---</option>' . "\n";  
    }  
    // Füge die Optionen-Zeichenkette und den End-Tag an die Rückgabe an  
    $output .= $options . "</select>\n";  
  
    // Gebe die Zeichenkette zurück, so dass an der Aufrufstelle beliebiges  
    // damit getan werden kann.  
    return $output;  
}  

Ich verzichte in der Funktion auf den Zugriff auf die superglobale Variable $_REQUEST. Erstens gebe ich den Inhalt nicht direkt aus, also benötige ich diesen nicht direkt und das Problem, dass es sich hier um gefährliche Daten handelt ist nicht gegeben. Weiterhin verzichte ich persönlich soweit als möglich (das heißt, fast immer) auf $_REQUEST. Ich weiß, über welchen Weg mein Formular die Daten übermittelt und genau diesen Weg frage ich ab :-)
Außerdem ist die Funktion somit leichter einsetzbar, z.B. für den Erstaufbau des Formulars mit einem Standardwert.

Dennoch ist der vorgestellte Code nur ein einfacher erster Entwurf. Selbstverständlich sollte die Funktion über eine etwas größere Parameterliste flexibler gestaltet werden:

- Wert des Name-Attributs,
 - Startwert,
 - Endwert,
 - Standardwert,
 - Standardanzeigewert, ...

die wiederum mit sinnvollen Werten vorbelegt sein könnten. Ideen gäbe es genug. Weiterhin lassen sich diverse Zeilen zusammenfassen, es ist ein erster Entwurf. Auch die Logik ließe sich ändern, so dass Du zuerst das erste <option>-Element mit dem Standardwert schreibst. Aber auf jeden Fall ist der
Code viel leichter lesbar, wenn Du je Schleifendurchlauf ein komplettes option-Element schreibst.

Und eh ich es vergesse: Ja, auch eine solch einfache Funktion, auch ein solch einfacher Code-Schnippsel sollte man ausführlich kommentieren. Kommentare erhöhen die Code-Qualität.

Aus Anwendersicht möchte ich Dir noch sagen, dass ich eine Datumsauswahl über diverse (typischerweise drei) SELECT-Elemente extrem benutzerunfreundlich finde. Wenn Du mal fünfhundert Datensätze über solche Formulare mit je drei Datumsangaben pro Datensatz ausgefüllen musstest, dann weißt Du anschließend, dass Du selbst das keinem Benutzer zumuten willst. Ein einfaches Textfeld mit einem kleinen Javascript-Kalenderchen ist meiner Meinung nach viel ergonomischer.

Ja, ich weiß, dass die Auswertung solcher Eingabefelder wesentlich höheren Aufwand bedeutet :-) Wenn Du das aber einmal *richtig* erledigt hast, dann ist das in Zukunft kein Aufwand mehr. Es wird einfach die entsprechende Prüfroutine, die z.B. eine Methode einer Klasse sein kann, aufgerufen und gut ist.

Freundliche Grüße

Vinzenz