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

Hallo liebe Forum-Leser,

für ein Kundenformular programmiere ich gerade eine Vakanzabfrage mit Datumsfeldern im Stil eines Affenformulars, damit Eingaben nicht verloren gehen. Die Zeitdaten werden select-Boxen angezeigt und um Schreibarbeit zu sparen natürlich mit for Schleife. Hier der Code-Snippet

  
print "<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>";  

Ich erwarte eine select-Box mit Werten von 0 (als -- dargestellt) bis 31, wobei im Falle der vorherigen Absendung der bereits gewählte Wert vorselektiert ist.

Ich bekomme eine select box mit Werten von 0 bis 31 mit jeweils 2er Sprung, also 1, 3, 5, 7, 9, 11 usw.

Leider sehe ich gerade den Fehler vor lauter Tomaten auf den Augen nicht mehr. Wäre sehr freundlich, wenn sich ein frischerer Geist als meiner die paar Zeilen gerade zu Gemüte führt. Herzlichen Dank!

Viele Grüße David

  1. Yerf!

    print "value="" . $i . ">" . $i ."</option>";

    Hm...

    Ich bekomme eine select box mit Werten von 0 bis 31 mit jeweils 2er Sprung, also 1, 3, 5, 7, 9, 11 usw.

    Schau dir doch mal im Browser den Quelltext an, vielleicht hilft das ja schon. Ansonsten sei als Tipp noch die oben genannte Zeile gegeben und der Hinweis auf den Value...

    Gruß,

    Harlequin

    --
    <!--[if IE]>This page is best viewed with a webbrowser. Get one today!<![endif]-->
    1. Hallo Harlequin,

      print "value="" . $i . ">" . $i ."</option>";

      Ich bekomme eine select box mit Werten von 0 bis 31 mit jeweils 2er Sprung, also 1, 3, 5, 7, 9, 11 usw.

      Schau dir doch mal im Browser den Quelltext an, vielleicht hilft das ja schon. Ansonsten sei als Tipp noch die oben genannte Zeile gegeben und der Hinweis auf den Value...

      Herzlichen Dank, das wars! Hatte das zweite " des values nicht geschlossen, sodass der darauf folgende Tag noch als value interpretiert wurde. Gab keine php-Fehlermeldung, aber eine falsche html-Ausgabe. Die berühmten Tomaten vor Augen ;-)

      Danke, Tschau!

  2. @@David:

    Leider sehe ich gerade den Fehler vor lauter Tomaten auf den Augen nicht mehr.

    Kein Wunder. Dein PHP-Code ist grottig.

    Erzeuge mit einer 'print'-Anweisung komplette HTML-Tags!

    Vor der Schleife den Anfang eines Tags erzeugen, in der Schleife dann mit einer 'print'-Anweisung den Rest und den Anfang des nächsten – also bitte, das ist miserabler Stil. Und fehleranfällig.

    Wie sieht das generierte HTML aus?

    Live long and prosper,
    Gunnar

    --
    „Das Internet ist ein großer Misthaufen, in dem man allerdings auch kleine Schätze und Perlen finden kann.“ (Joseph Weizenbaum)
    1. Hallo Gunnar,

      Kein Wunder. Dein PHP-Code ist grottig.

      Erzeuge mit einer 'print'-Anweisung komplette HTML-Tags!

      Vor der Schleife den Anfang eines Tags erzeugen, in der Schleife dann mit einer 'print'-Anweisung den Rest und den Anfang des nächsten – also bitte, das ist miserabler Stil. Und fehleranfällig.

      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).

      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:

        
      <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>  
      
      

      Danke und viele Grüße, David

      1. Hi,

        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:

        <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>

          
          
        ~~~php
        <select name="from_day">  
        <?php  
          $selected = [link:http://www.php.net/manual/de/language.operators.comparison.php@title=($_REQUEST['from_day'\]=='0') ? ' selected' : ''];  
          echo '<option'.$selected.' value="0">--</option>';  
          
          for ($i=1; $i<=31; $i++) {  
            $selected = ($_REQUEST['from_day']==$i) ? ' selected' : '';  
            echo '<option'.$selected.' value="'.$i.'">'.$i.'</option>';  
          }  
        ?>  
        </select>
        

        MfG ChrisB

        1. echo $begrüßung;

          Alternativvorschläge:

          $selected = ($_REQUEST['from_day']=='0') ? ' selected' : ''];
            echo '<option'.$selected.' value="0">--</option>';

          printf('<option %s value="0">--</option>',
            $_REQUEST['from_day'] == '0' ? 'selected="selected"' : '');

          $selected = ($_REQUEST['from_day']==$i) ? ' selected' : '';
              echo '<option'.$selected.' value="'.$i.'">'.$i.'</option>';

          printf('<option %s value="%s">%s</option>',
            $_REQUEST['from_day'] == $i ? 'selected="selected"' : '', $i, $i);

          echo "$verabschiedung $name";

          1. Hallo Vinzenz, Chris und Dedlfix,

            herzlichsten Dank für diese auführlichen Anwtworten. Insebesondere die Funktionsbibliothek von Vinzenz scheint mir ja schon ein Tutorial zu sein. Mit so viel Mühe und Liebe zum Detail hätte ich nicht gerechnet, obwohl ich das Forum aufmerksam verfolge.

            Ich werde mir alle vorgeschlagenen Lösungen genauer zu Gemüte führen und mein Script unter diesen Gesichtspunkten nochmal völlig neu angehen. Das allerdings leider in meiner Freizeit, denn die Agentur zahlt den zusätzlichen Aufwand, um sauber und logisch strukturiert zu programmieren, nur in den seltensten Fällen. Aber danach habe ich eine Art Muster Script, dass ich dann für den jeweiligen Fall anpassen kann und mit dem ich mich deutlich besser fühle.

            Also nochmal herzlichen Dank für Eure Mühe. Ich hoffe in ein paar Tagen sagen zu können, dass sie nicht vergeblich war ;-)

            Freundliche Grüße
            David

      2. 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