Ankündigung

Einklappen
Keine Ankündigung bisher.

Codeoptimierung:Code-Smells

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Codeoptimierung:Code-Smells

    Diskussionsbeitrag zum Wiki Eintrag: Codeoptimierung:Code-Smells.

    Die Diskussionsplattform des PHP.de Wiki wurde ins Forum integriert. Durch Klicken des Buttons "Antwort" kannst du an diesem Thema teilnehmen.
    --

    „Emoticons machen einen Beitrag etwas freundlicher. Deine wirken zwar fachlich richtig sein, aber meist ziemlich uninteressant.
    Wenn man nur Text sieht, haben viele junge Entwickler keine interesse, diese stumpfen Texte zu lesen.“


    --


  • #2
    Die Bar ist eröffnet
    --

    „Emoticons machen einen Beitrag etwas freundlicher. Deine wirken zwar fachlich richtig sein, aber meist ziemlich uninteressant.
    Wenn man nur Text sieht, haben viele junge Entwickler keine interesse, diese stumpfen Texte zu lesen.“


    --

    Kommentar


    • #3
      SELECT *:
      Aus der Datenbanktabelle wird hier stets jedes Feld der Zeile abgefragt. Meistens ist das gar nicht nötig, weil nur ein Teil der Felder verarbeitet wird.
      Das kontert jeder Newbie mit „doch, ich brauche die Felder alle“.

      Deshalb vllt. noch um einen Hinweis ergänzen, dass auch in die Zukunft geplant werden sollte - damit nicht die BLOB-Spalte, die irgendwann mal dazu kommt, auch jedes Mal vom DB-Server nach PHP rübergewuchtet werden muss, auch wenn sie nicht benötigt wird.

      Kommentar


      • #4
        Notiz an mich selbst: JOIN vs. DB-Abfragen in Schleifen
        --

        „Emoticons machen einen Beitrag etwas freundlicher. Deine wirken zwar fachlich richtig sein, aber meist ziemlich uninteressant.
        Wenn man nur Text sieht, haben viele junge Entwickler keine interesse, diese stumpfen Texte zu lesen.“


        --

        Kommentar


        • #5
          Zitat von Flor1an
          PHP-Code:
          <?php
          for ($i 0$i++; $i5) {
            
          $name 'file_'.$i;
            $
          $name $_FILES['datei_'.$i];
          }
          keine variablen Variablen nutzen und zum anderen in Formularen auch Arrays nutzen.

          Gruß Flo
          --

          „Emoticons machen einen Beitrag etwas freundlicher. Deine wirken zwar fachlich richtig sein, aber meist ziemlich uninteressant.
          Wenn man nur Text sieht, haben viele junge Entwickler keine interesse, diese stumpfen Texte zu lesen.“


          --

          Kommentar


          • #6
            SELECT *:
            ... Folgefehler (Zugriff auf nicht mehr existente Feldnamen) ...
            Das verstehe ich nicht. Wie kann man mit SELECT * auf nicht mehr existierende Feldnamen zugreifen? Das kann doch nur dann passieren, wenn man kein SELECT * verwendet. Oder was ist mit der Aussage gemeint?

            Edit:
            Ich hab mir jetzt auch mal den Rest angesehen und dabei ist mir auch "LIMIT und Schleife" aufgefallen. Ein LIMIT 1 bei einer Abfrage auf einen Primärschlüssel ergibt für mich ebenfalls keinen Sinn. Das ist unnötig, weil es nur ein Ergebnis geben kann. Damit kaschiert man höchsten erhebliche Mängel im Datenbankdesign.

            Kommentar


            • #7
              Ich nachfolgenden Code.. du machst $row['foo'] und weiß nicht (mehr) das es foo nicht mehr gibt, findest es aber erst nach einigem debuggen raus das der Ursprung des Bösen ist das es das "oben" nicht (mehr) gibt.
              Debugging: Finde DEINE Fehler selbst! | Gegen Probleme beim E-Mail-Versand | Sicheres Passwort-Hashing | Includes niemals ohne __DIR__
              PHP.de Wissenssammlung | Kein Support per PN

              Kommentar


              • #8
                OK, danke. Ich verstehe jetzt wie es gemeint ist. Allerdings empfinde ich das Argument konstruiert. Man erhält in diesem Fall eine Undefined index: foo Warnung, die ganz genau Auskunft über das Problem gibt.

                Selbst wenn man die Datenbankänderung vergessen hat oder sie von jemand anderem durchgeführt wurde, so wird man nach der Änderung auch die SQL Statements anpassen müssen. Sobald die geändert sind, unterscheidet sich die Situation aber nicht mehr von einem SELECT *. Wenn irgendwo im Code auf $row['foo'] zugegriffen wird, wird eine Warnung generiert und es macht dann überhaupt keinen Unterschied wie das SQL Statement aussieht.

                Kommentar


                • #9
                  Man sollte auf den "all"-Select verzichten und explizit angeben welche Felder man haben möchte damit man in erster Linie weiß was wo angefordert wird und man es leicht(er) anpassen kann. Es ist eigentlich schiere Faulheit die gewünschten Felder nicht aufzuführen. Bei komplexeren Queries wirst du auch Feld-Aliase nutzen, damit du bei Assoziativen Arrays oder Object-Injection direkter arbeiten kannst, das ist allerdings nicht mit dem All-Fields-Selector (*) möglich.

                  Anwendungen die Zentralisiert ihre Queries speichern ( bspw. in YAML-Files, wie ich das tuhe, wodurch ich über einen Pimple-Container entsprechend auf die Queries zugreif.. ), abstrahieren ihre Queries mitunter ( wenns kein ORM-System oder andere "Helfer" nutzen ) sodass Teile von Queries entsprechend auch wiederverwendet werden können.

                  Code:
                  ---
                  
                  # base query
                  foo: *foo |
                  SELECT
                     a,
                     b,
                     c,
                     d,
                     e,
                  FROM foobar;
                  
                  foobar: # will be auto-join(' ', therms)'ed within container mechanics
                  
                     &foo
                  
                     -: |
                        WHERE a = :a LIMIT 12
                  
                  bazbar: # will be auto-join(' ', therms)'ed within container mechanics
                  
                     &foo
                  
                     -: |
                        WHERE b = :b LIMIT 100
                  PHP-Code:
                  $prep $app['database']->prepare($app['queries']['bazbar']);
                  /* ... */ 
                  Aus Entwicklungstechnischer sicht ist es unsauber alles via * zu selektieren, da du dich so blind auf die Datenbank-Struktur verlässt, was bei minimalen Änderungen zum Programmabbruch führen könnte, da plötzlich Felder nicht mehr da sind, die mal da waren.
                  [URL="https://gitter.im/php-de/chat?utm_source=share-link&utm_medium=link&utm_campaign=share-link"]PHP.de Gitter.im Chat[/URL] - [URL="https://raindrop.io/user/32178"]Meine öffentlichen Bookmarks[/URL] ← Ich habe dir geholfen ? [B][URL="https://www.amazon.de/gp/wishlist/348FHGUZWTNL0"]Beschenk mich[/URL][/B].

                  Kommentar


                  • #10
                    Hi Tr0y,

                    ich stelle nicht den Sinn oder Unsinn von SELECT * in Frage. Daher pflichte ich dem oberen Abschnitt deines Postings bei.

                    Mir geht es lediglich um diesen Teil:
                    Aus Entwicklungstechnischer sicht ist es unsauber alles via * zu selektieren, da du dich so blind auf die Datenbank-Struktur verlässt, was bei minimalen Änderungen zum Programmabbruch führen könnte, da plötzlich Felder nicht mehr da sind, die mal da waren.
                    Ein Programmabbruch wird nicht durch SELECT * verursacht. Ein Programmabbruch wird aber verusacht, wenn man im SQL Statement explizit Felder abfragt, die nicht existieren. Korrigiert man das SQL Statement, können die Folgefehler ebenso bei der expliziten Angabe der Felder auftreten. Ein Zugriff auf $row['foo'] oder $object->foo wird zu einer Warnung führen, ganz egal wie das SQL Statement aussieht.

                    Das Problem SELECT * anzulasten ist quatsch, da es auch auftritt, wenn man kein SELECT * benutzt.

                    Kommentar


                    • #11
                      Ich habe auch mal wo gelesen das es unperformanter ist weil MySQL "intern" bei einem SELECT * zuerst "schauen" muss was es gibt und dann abholt, bei einer definierten Anforderung aber gleich direkt abholt. Das hab ich aber nie genau hinterfragt und/oder ge-benchmarkt, weil ich sowieso nie anders mache...

                      Abgesehen davon hast du ev. 100 Spalten/Felder und brauchst nur 10, im Result das du dann erhältst (also die DB-Daten-Array) hast du dann halt die volle Latte drinnen, was ev. auch wieder auf "Performance" (in dem Fall halt Memory) sich auswirkt.

                      Falls dich das Argument Performance interessiert findest du sicher einiges dazu via Tante G.
                      Debugging: Finde DEINE Fehler selbst! | Gegen Probleme beim E-Mail-Versand | Sicheres Passwort-Hashing | Includes niemals ohne __DIR__
                      PHP.de Wissenssammlung | Kein Support per PN

                      Kommentar


                      • #12
                        Zitat von cyro Beitrag anzeigen
                        Hi Tr0y,

                        ich stelle nicht den Sinn oder Unsinn von SELECT * in Frage. Daher pflichte ich dem oberen Abschnitt deines Postings bei.

                        Mir geht es lediglich um diesen Teil:


                        Ein Programmabbruch wird nicht durch SELECT * verursacht. Ein Programmabbruch wird aber verusacht, wenn man im SQL Statement explizit Felder abfragt, die nicht existieren. Korrigiert man das SQL Statement, können die Folgefehler ebenso bei der expliziten Angabe der Felder auftreten. Ein Zugriff auf $row['foo'] oder $object->foo wird zu einer Warnung führen, ganz egal wie das SQL Statement aussieht.

                        Das Problem SELECT * anzulasten ist quatsch, da es auch auftritt, wenn man kein SELECT * benutzt.
                        Doch .. genau ist das ein Problem spezifisch von SELECT * .. hier WEISST du nämlich gar nicht, welche Spalten kommen (sollen) ... du bist "blind" der Datenbank ausgeliefert.
                        Und beim Debuggen hängst du dann "warum zum Geier geht $row['foo'] nicht (mehr) die hat doch noch vorgestern (ja - vor dem herumschrauben an der Tabelle, seit dem foo eben `funktionsanalyseparameter` heißt) - in PHP siehst du dann eben undefined index - aber die Fehlermeldung der Datenbank wäre viel aussagekräftiger "you have an error in you SQL syntax , unknown column `foo` - da weißt du gleich, dass es daran hängen muss ... die PHP-Meldung bekommt man gerade als Änfänger im rohen Dutzend um die Ohren gehauen - mit exakt dem gleichen Fehlertext (weil das uralt-Tutorial sich vielleicht auf register globals=on berufen hat )...da ist schon viel geholfen, wenn du die Quelle dieses Fehlers exakt kennst

                        @hausl ... nicht wirklich .. der Parser muss so oder so schauen, welche Spalten da sind, um sie dann mit der Liste abzugleichen, die du beim Select angibst - oder eben nicht ...die Auswirkung dürfte eher im Bereich der Messbarkeitsgrenze liegen, zumal der Parser mit das best optimierte an Datenbanken ist

                        Ein weiteres Argument gegen Select * ist definitiv der mögliche Speicherbedarf, wenn zum Beispiel Blob oder longtext-Spalten mit beteiligt sind - und auch noch mehr als 1 Datensatz ermittelt wird
                        Zitat von nikosch
                        So glatt kann doch wirklich keiner sein.

                        Kommentar


                        • #13
                          Zitat von cyro Beitrag anzeigen
                          Hi Tr0y,

                          ich stelle nicht den Sinn oder Unsinn von SELECT * in Frage. Daher pflichte ich dem oberen Abschnitt deines Postings bei.

                          Mir geht es lediglich um diesen Teil:


                          Ein Programmabbruch wird nicht durch SELECT * verursacht. Ein Programmabbruch wird aber verusacht, wenn man im SQL Statement explizit Felder abfragt, die nicht existieren. Korrigiert man das SQL Statement, können die Folgefehler ebenso bei der expliziten Angabe der Felder auftreten. Ein Zugriff auf $row['foo'] oder $object->foo wird zu einer Warnung führen, ganz egal wie das SQL Statement aussieht.

                          Das Problem SELECT * anzulasten ist quatsch, da es auch auftritt, wenn man kein SELECT * benutzt.
                          Ach ja? Stell dir vor, du dividierst einen beliebigen Wert durch einen Wert, der du aus der DB holst. Jetzt kommt da aber nichts, weil das Feld nicht mehr da ist ( also (null) ). Da wären wir schon bei einem Fatal-Error: dividide by zero.

                          Du bekommst also ein unerwartetes Verhalten und kannst nicht auf die möglicherweise entstehenden Fehler reagieren, weil du nicht weist, welche Fehler entstehen könnten.

                          Wenn du jedoch Felder holst, die nicht da sind erhälst du einen erwarteten Fehler: column not found.

                          Deshalb schon aus diesem Grund niemals * anwenden, weil du dann die Anwendung nicht mehr unter Kontrolle hast.
                          GitHub.com - ChrisAndChris - RowMapper und QueryBuilder für MySQL-Datenbanken

                          Kommentar


                          • #14
                            Nagut, dann halt ein einfaches Beispiel:

                            PHP-Code:
                            function getUser($id) {
                              
                            // connect, variablenbehandlung, etc. 

                              
                            $ress mysql_query("SELECT `Id` , `Name` FROM Personen WHERE id=$id");
                              if(
                            $data mysql_fetch_assoc($ress)) {
                                return 
                            $data;
                              }
                              return 
                            false;
                            }

                            // eigentlicher code
                            // derartige zugriffe können vielfach in einem projekt verstreut sein
                            if ($user getUser($id)) {
                              echo 
                            $user['login']; // BOOM

                            Es spielt überhaupt keine Rolle, ob im SQL Statement ein SELECT * steht oder nicht. Der Folgefehler hat mit dem SQL Statement überhaupt nichts zu tun. Der Programmcode muss nicht immer in der While Schleife hinter der Datenbankabfrage stehen. Und selbst dann, muss der Zugriff auf die Variable auch bei einer expliziten Abfrage geändert werden. Der Verzicht auf SELECT * schützt einen vor den Folgefehlern nicht. Daher ist die Aussage mit den Folgefehlern falsch.

                            Ein weiteres Argument gegen Select * ist definitiv der mögliche Speicherbedarf, wenn zum Beispiel Blob oder longtext-Spalten mit beteiligt sind - und auch noch mehr als 1 Datensatz ermittelt wird
                            Sehe ich genauso. Wobei das eher von einem schlechten Datenbankdesign zeugt. Solche Fehler im Programmcode auszubügeln geht nur eine bestimmte Zeit lang gut.

                            Kommentar


                            • #15
                              Na ja, dein Argument ist jetzt aber: „Es ist sinnfrei, auf die Korrektheit von Schnittstellenrückgaben zu achten, denn mich hält nichts davon ab, später im Code einen Tippfehler in einem Variablennamen zu haben.“

                              Ich weiß nicht, ob das so produktiv ist.



                              Randaspekt: Der Wiki-Artikel ist sicherlich nicht unbedingt für Profi-Entwickler gedacht, die ihren Code „vollständig“ mit Unit-Tests abgedeckt haben und die dazu noch eine Nachricht erhalten, falls in einer Anwendung mal irgendwo eine PHP Notice geworfen wird.
                              PHP-Wissenssammlung Composer Awesome Awesomeness PHP: The Right Way @mermshaus

                              Kommentar

                              Lädt...
                              X