Announcement

Collapse
No announcement yet.

Bug im PHP-Befehl COUNT() ???

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Bug im PHP-Befehl COUNT() ???

    Hallo,

    ich bin gerade an einer simplen Problem-Stellung, die ich so und ähnlich vermutlich schon 100 mal programmiert habe, verzweifelt. Ich weiß nicht, ob es sich um einen Bug in PHP handelt oder ich irgendetwas nicht berücksichtige. Bitte schaut Euch mal folgenden Code an:

    PHP Code:
    $line_anz count(${$quell_tab_name});

    if(
    $line_anz)
    {
     
    $ele_counter 0;
     
    $ele_filled_counter 0;

     while(
    $ele_filled_counter $line_anz)
     {
      if(isset(${
    $quell_tab_name}[$ele_counter]))
      {
       echo 
    "Hier wird das gefüllte Element weiterverarbeitet";

       ++
    $ele_filled_counter;
      }

      ++
    $ele_counter;
     }

    Erwartet hätte ich, dass er für alle gefüllten Elemente in das innere IF-Statement geht und die dortige Verarbeitung vornimmt (Im Beispiel das echo ausgibt). Dadurch muss der Counter $ele_filled_counter irgendwann zwangsläufig den Wert von $line_anz erreichen und die Schleife verlassen werden. Das geschieht aber im aktuellen Beispiel nicht. Er läuft durch bis zum Index 4294967296 (4GB, offensichtlich habe ich einen 32-Bit Betriebssystem), welcher dann wieder auf Index 0 verweist. Dadurch findet er dann wieder gefüllte Elemente (die er beim ersten Durchlauf schon gezählt hat) und erst dann verlässt er dann irgendwann die Schleife. Der Count-Befehl liefert also ein anderes (höheres) Resultat, als der komplette Durchlauf sämtlicher denkbaren Elemente des Arrays und Prüfung mit ISSET(). WARUM?

    Ich weiß, dass es weitere Möglichkeiten gibt (foreach-Schleife oder die Ermittlung des letzten Indizes im Array über key(), aber darum geht es mir nicht. Ich würde gerne verstehen, warum die Logik oben nicht funktioniert. Normalerweise tut sie das einwandfrei, auch bei Unset-Elementen in der Tabelle. Aktuell muss aber irgendein Spezial-Fall vorliegen, wo es nicht funktioniert.

    Für Tipps schon im Voraus vielen Dank,
    Michael
    Zuletzt editiert von Duftox; 26.04.2013, 20:51.

  • #2
    Es wird wohl - solange $ele_filled_counter noch kleiner ist als $line_anz die - if(isset(${ -Bedingung nicht mehr zutreffen. Somit wird ab irgendeinen Zeitpunkt nur noch ++$ele_counter ausgeführt. Der Wert von $ele_filled_counter nicht mehr erhöht. Erreicht tatsächlich$ele_filled_counter diesen hohen Wert und nicht ++$ele_counter?

    Die while-Bedingung sollte auf $ele_counter lauten und nicht auf $ele_filled_counter, da dieser nur unter einer Bedingung erhöht wird. $ele_counter sollte die tatsächliche Anzahl enthalten, egal ob bearbeitet oder nicht

    Des Weiteren einfach mal debuggen
    Zuletzt editiert von Christian Marquardt; 27.04.2013, 07:55.
    Christian

    Comment


    • #3
      Hi Christian,

      vorausgesetzt, dass es bei mir gedanklich gerade nicht völlig hakt, muss ich Dir widersprechen. Die Abfrage muss meines Erachtens schon auf $ele_filled_counter lauten.

      Um das Ganze etwas plastischer zu gestalten, stellen wir uns doch einfach mal einen konkreten Tabellen-Inhalt vor, zum Beispiel:

      PHP Code:
      unset($tab);

      $tab[0] = 'A';
      $tab[5] = 'B';
      $tab[7] = 'C';

      $quell_tab_name 'tab'
      Wenn nun der oben gepostete Source durchlaufen wird, sollte der Count() doch 3 liefern. Der $ele_counter startet von 0 und direkt beim ersten Durchlauf ist die innere IF-Bedingung erfüllt und der $ele_filled_counter wird auf 1 erhöht. Nun bedarf es 4 weiterer Schleifen-Durchläufe, in denen nur der $ele_counter erhöht wird, bis beim Index 5 erneut $ele_filled_counter erhöht wird. Beim Index 7 geschieht das dann das dritte und letzte mal, sodass $ele_filled_counter den Wert 3 annimmt, während $ele_counter (unnötigerweise) am Schluss der Schleife noch mal von 7 auf 8 erhöht wird, bis dann in der kopfgesteuerten Schleife erkannt wird, dass $ele_filled_counter (=3) nicht mehr kleiner $line_anz (=3) ist und diese daher verlassen wird. Diese Schleife muss also eigentlich immer zu einem Ende kommen, es sei denn, meine Grundannahme ist falsch, dass der Count() immer die ISSET() Elemente eines Arrays zurück gibt.

      Zu Deiner Frage: Der $ele_counter wird bis zum Wert 2hoch32 hochgezählt, bis dann danach der Index 4294967296 wieder auf das gleiche Array-Element wie Index 0 verweist.

      Leider besitze ich keinen Debugger, bisher habe ich den (trotz aktueller Größe meines Projektes von 6mb Source-Code) noch nie so vermisst, dass ich mich schlau gemacht habe, welche Produkte da geeignet sind. Im aktuellen Fall wäre ein Einzelschritt-Debugger aber sicher sehr hilfreich gewesen.

      Ich werde mir das ganze jetzt noch mal genauer anschauen. Aber wer weitere Anregungen hat, ruhig her damit.

      Gruß
      Michael

      Comment


      • #4
        In deinem ersten Post ist es noch $ele_filled_counter welches diesen hohen Wert annimmt, jetzt $ele_counter.

        Ev. wird $ele_filled_counter in der "weiteren Bearbeitung" noch geändert
        Christian

        Comment


        • #5
          Originally posted by Christian Marquardt View Post
          In deinem ersten Post ist es noch $ele_filled_counter welches diesen hohen Wert annimmt, jetzt $ele_counter.
          Ich habe nie explizit gesagt, dass es $ele_filled_counter ist, welches diesen hohen Wert annimmt. Ich gebe Dir aber recht, dass ich mich missverständlich ausgedrückt habe.

          Ich habe inzwischen aber die Lösung des Problems gefunden. Es ist doch immer wieder überraschend, wie logisch einem die Dinge morgens erscheinen, die am Vorabend nach 10 Stunden Arbeit so verworren zu sein scheinen ;-)

          PHP Code:
          unset($tab);
          unset(
          $var);

          $tab[0]=$var;

          echo 
          count($tab); 
          Die Ausgabe lautet 1!

          Somit war meine Grundannahme also falsch. Count() liefert eben nicht die Anzahl der gefüllten Array-Elemente, sondern auch Array-Elemente die UNSET sind werden mitgezählt. Diese Eigenart hat mir schon häufiger ein Bein gestellt, ich kann mir das einfach nicht merken, weil es mir irgendwie unlogisch erscheint. Warum legt er für ein nicht gesetztes Feld schon ein Element im Array an? Wäre es nicht logischer, dass einfach sein zu lassen?

          Viele Grüße
          Michael

          Comment


          • #6
            Dadurch muss der Counter $ele_filled_counter irgendwann zwangsläufig den Wert von $line_anz erreichen und die Schleife verlassen werden. Das geschieht aber im aktuellen Beispiel nicht. Er läuft durch bis zum Index 4294967296
            Ich habe nie explizit gesagt, dass es $ele_filled_counter ist, welches diesen hohen Wert annimmt.
            Sicherlich hast du das s.o.
            Christian

            Comment


            • #7
              Dadurch muss der Counter $ele_filled_counter irgendwann zwangsläufig den Wert von $line_anz erreichen und die Schleife verlassen werden. Das geschieht aber im aktuellen Beispiel nicht. Er läuft durch bis zum Index 4294967296
              Ich habe nie explizit gesagt, dass es $ele_filled_counter ist, welches diesen hohen Wert annimmt.
              Sicherlich hast du das s.o. Auf wen könnte sich sonst "er" beziehen
              Christian

              Comment


              • #8
                Weiß jemand noch eine Antwort auf meine Frage oben? Warum legt PHP im Beispiel oben (#5) ein Array-Element für Index 0 an, aber ISSET($tab[0]) ist FALSE? Ist das sinnvoll? Mich hat dieses Verhalten bisher immer nur gestört, hat diese Eigenart auch irgendwelche positiven/nützlichen Aspekte?

                Comment


                • #9
                  Weil du ein indiziertes Array hast und kein assoziatives
                  Christian

                  Comment


                  • #10
                    Hi Christian,

                    das beantwortet aber nicht wirklich meine Frage, warum ein Element angelegt wird. Mir leuchtet die von Dir implizierte, scheinbar zwangsläufige Abhängigkeit von indiziertem Array und Element ohne Inhalt nicht unbedingt ein, gebe aber auch gerne zu, dass ich von der Technik, die dahinter steckt, nicht unbedingt viel verstehe. Ich wende sie als Entwickler nur an.

                    Aber auch bei assoziativen Arrays habe ich genau den selben Effekt. Folgendes kleine Test-Programm:

                    PHP Code:
                    <?php

                    unset($tab);
                    unset(
                    $var);

                    $tab['hallo'] = $var;

                    echo 
                    count($tab);

                    if(!isset(
                    $tab['hallo']))
                    {
                     echo 
                    "<br>Nicht gesetzt<br>";
                    }

                    unset(
                    $tab['hallo']);

                    echo 
                    count($tab);
                    ?>
                    ...liefert den folgenden Output:

                    1
                    Nicht gesetzt
                    0


                    Also ich finde das merkwürdig! Wie kann ein UNSET auf ein Array-Element, das gar nicht gesetzt ist, die Anzahl der Array-Elemente reduzieren?

                    Comment


                    • #11
                      Wo ist das Problem?

                      $tab['hallo'] = $var;

                      Array Länge 1

                      unset($tab['hallo'])

                      gelöscht, Länge 0 -> alles ok

                      Du reservierst doch erstmal im dem Array einen Platz.

                      Wenn es dir um $var geht, http://php.net/manual/de/function.unset.php hängt es davon ab, wo diese definiert wurde.


                      Gut, mache in PHP nicht so viel, aber darüber bin ich noch nicht gefallen
                      Zuletzt editiert von Christian Marquardt; 28.04.2013, 19:32.
                      Christian

                      Comment


                      • #12
                        Originally posted by Duftox View Post
                        ...Also ich finde das merkwürdig! Wie kann ein UNSET auf ein Array-Element, das gar nicht gesetzt ist, die Anzahl der Array-Elemente reduzieren?
                        Hallo,
                        dein Problem ist ein falsches Verständnis der Prüfung mit ISSET(). Die Kernaussage im Manual ist:
                        Originally posted by http://de1.php.net/manual/de/function.isset.php
                        Prüft, ob eine Variable existiert und nicht NULL ist.
                        ISSET liefert also auch dann FALSE, wenn eine Variable (oder ein Array-Eintrag) zwar existiert, aber eben NULL ist!
                        Die Zuweisung eines NULL-Wertes an einen Array-Eintrag löscht diesen ja nicht, sondern setzt ihn lediglich auf NULL, also undefiniert. Alles andere wäre nach meinem Verständnis auch Unsinn.

                        Mit deinem
                        PHP Code:
                        unset($tab);
                        unset(
                        $var);

                        $tab['hallo'] = $var
                        weist du dem Array-Eintrag $tab['hallo'] lediglich ein NULL zu, du löschst diesen Eintrag jedoch nicht. Eine Prüfung mit
                        PHP Code:
                        isset($tab['hallo']) 
                        liefert zwar FALSE, aber nicht weil $tab['hallo'] nicht existiert, sondern weil es NULL ist. Eine korrekte Prüfung ob ein Array-Eintrag existiert, sollte deshalb immer mit der Prüfung auf den Array-Schlüssel erfolgen, also mit array_key_exists().
                        Damit macht dann auch dein Bsp. Sinn.
                        PHP Code:
                        <?php
                        unset($tab);
                        unset(
                        $var);

                        $tab['hallo'] = $var;

                        unset(
                        $tab);
                        unset(
                        $var);

                        $tab['hallo'] = $var;

                        echo 
                        count($tab);

                        if(!
                        array_key_exists('hallo'$tab))
                        {
                         echo 
                        "<br>Nicht gesetzt<br>";
                        }

                        unset(
                        $tab['hallo']);

                        echo 
                        count($tab);
                        Ergebnis:
                        1
                        0

                        Gruß Falk
                        Wenn du denkst du hast alle Bugs gefunden, dann ist das ein Bug in deiner Denksoftware.

                        Quellcode ohne ein Mindestmaß an Formatierung sehe ich mir nicht an! Ich leiste keinen Privatsupport per Mail oder PN!

                        Comment


                        • #13
                          Hi Falk,

                          array_key_exists kannte ich nicht, das ist gut zu wissen, dass da ein kleiner aber feiner Unterschied zum ISSET() existiert. Dieser Befehl ist demnach das korrekte Pendant zum COUNT(), somit wäre mein Ursprungsproblem gelöst.

                          Wenn ich Eure Geduld damit nicht überstrapaziere, würde ich aber gern nochmal eine andere Frage stellen, die ich oben schon angesprochen habe: Gibt es irgendeinen Grund, warum PHP ein Array-Element für NULL reserviert? Könnte es irgendeine Situation geben, wo ich zwischen NULL (also nicht definiert) und nicht existent unterscheiden wollen würde?

                          Ich programmiere zwar noch nicht besonders lange in PHP, aber bisher war für mich immer nur die Frage wichtig, ob ich Inhalt habe oder ob ich keinen Inhalt habe. Bei einer normalen Variable habe ich doch auch nur diese zwei Zustände, ISSET oder !ISSET. Warum habe ich dann bei einem Array-Element quasi drei mögliche Zustände: 1) !Array_Key_exists 2) Array_Key_exists und !ISSET, 3) ISSET.

                          Vielen Dank für Eure Hilfe,
                          Gruß
                          Michael

                          Comment


                          • #14
                            Hallo,

                            wie gesagt alles eine Frage des Verständnisses . Im Endeffekt hat natürlich auch der Wert NULL seine Bedeutung - wozu gäbe es ihn sonst. Auch deine Betrachtung der "zwei Zustände" von "normalen Variablen" ist zu kurz gedacht. Eine Variable verschwindet NICHT indem man sie Null setzt! Du glaubst das nur, weill du der gleichen falschen Aussage von isset vertraust. Wenn du nämlich die wahre Existenz einer Variable über get_defined_vars() prüfst, dann erhälst du das gleiche Verhalten wie bei Arrays.

                            PHP Code:
                            <?php

                            $myVar       
                            1234;

                            unset(
                            $myVar);
                            $mySecondVar $myVar;

                            echo 
                            array_key_exists('myVar'get_defined_vars()) ? 'myVar existiert' 'myVar existiert nicht';
                            echo 
                            array_key_exists('mySecondVar'get_defined_vars()) ? 'mySecondVar existiert' 'mySecondVar existiert nicht';
                            Ergebnis:
                            Code:
                            myVar existiert nicht
                            mySecondVar existiert
                            Gruß Falk
                            Wenn du denkst du hast alle Bugs gefunden, dann ist das ein Bug in deiner Denksoftware.

                            Quellcode ohne ein Mindestmaß an Formatierung sehe ich mir nicht an! Ich leiste keinen Privatsupport per Mail oder PN!

                            Comment


                            • #15
                              Genial, so ergibt das alles Sinn. Nach wie vor kann ich mir zwar keine Situation vorstellen, wozu ich NULL bei einer Variable brauchen würde, aber nur weil ich mir das nicht vorstellen kann, heißt es ja nicht, dass es irgendwo sinnvoll angewendet werden kann. Zumindest bin ich Dir dankbar, dass Du mein falsches Verständnis bezüglich UNSET & Co. da korrigiert hast.

                              Viele Grüße
                              Michael

                              Comment

                              Working...
                              X