Sophie: PHP Funktion zweimal verwenden?

Guten Morgen,

ich beschäftige mich derzeit mit Funktionen. Dazu hätte ich eine Frage.

function firmen($mysqli) {

$stmt = $mysqli->prepare("SELECT id, code, firma, abteilung, sort, ab_an, signup_an, intern FROM firmen WHERE signup_an = 1 AND intern = 0  ORDER by sort ASC");

$stmt->execute();
$stmt->bind_result($id, $code, $firma, $abteilung, $sort, $ab_an, $signup_an, $intern);
$stmt->store_result();
        
if($stmt->num_rows() >  0) {

    while ($stmt->fetch()){
        
          $firmen[] = array( 
            'id'          => $id, 
            'code'        => $code, 
            'firma'       => $firma,
            'abteilung'   => $abteilung,
            'sort'        => $sort,
            'ab_an'       => $ab_an,
            'signup_an'   => $signup_an,
            'intern'      => $intern );
        }
        return $firmen;
    }
}

Ich würde gerne diese Funktion an zwei Stellen verwenden. Soweit kein Problem. Allerdings sollte an der zweiten Stelle, alle Firmen ausgelesen werden, das AND intern = 0 ist demzufolge störend.

Habe ich die Möglichkeit dieses mit einer Funktion zu machen oder muss ich diese kopieren und unter einem anderen Namen abspeichern?

  1. Hello,

    function firmen($mysqli) {
    
    $stmt = $mysqli->prepare("SELECT id, code, firma, abteilung, sort, ab_an, signup_an, intern FROM firmen WHERE signup_an = 1 AND intern = 0  ORDER by sort ASC");
    
    $stmt->execute();
    $stmt->bind_result($id, $code, $firma, $abteilung, $sort, $ab_an, $signup_an, $intern);
    $stmt->store_result();
            
    if($stmt->num_rows() >  0) {
    
        while ($stmt->fetch()){
            
              $firmen[] = array( 
                'id'          => $id, 
                'code'        => $code, 
                'firma'       => $firma,
                'abteilung'   => $abteilung,
                'sort'        => $sort,
                'ab_an'       => $ab_an,
                'signup_an'   => $signup_an,
                'intern'      => $intern );
            }
            return $firmen;
        }
    }
    

    Ich würde gerne diese Funktion an zwei Stellen verwenden. Soweit kein Problem. Allerdings sollte an der zweiten Stelle, alle Firmen ausgelesen werden, das AND intern = 0 ist demzufolge störend.

    Habe ich die Möglichkeit dieses mit einer Funktion zu machen oder muss ich diese kopieren und unter einem anderen Namen abspeichern?

    Du könntest auch die Statements außerhalb der Abfrage vorbereiten und dann bitte auch mit einem sinnvollen Namen versehen und als zusätzlichen Parameter mitgeben.

    
    $stmt_interne_firmen = $mysqli->prepare("SELECT id, code, firma, abteilung, sort, ab_an, signup_an, intern FROM firmen WHERE signup_an = 1 AND intern = 0  ORDER by sort ASC");
    
    $stmt_alle_firmen = $mysqli->prepare("SELECT id, code, firma, abteilung, sort, ab_an, signup_an, intern FROM firmen WHERE signup_an = 1 ORDER by sort ASC");
    
    function firmen($mysqli, $stmt) 
    {
    
    ### ...
    
    } 
    
    

    Liebe Grüße
    Tom S.

    --
    Es gibt nichts Gutes, außer man tut es
    Andersdenkende waren noch nie beliebt, aber meistens diejenigen, die die Freiheit vorangebracht haben.
  2. Hallo

    ich beschäftige mich derzeit mit Funktionen. Dazu hätte ich eine Frage.

    Ich würde gerne diese Funktion an zwei Stellen verwenden. Soweit kein Problem. Allerdings sollte an der zweiten Stelle, alle Firmen ausgelesen werden, das AND intern = 0 ist demzufolge störend.

    Habe ich die Möglichkeit dieses mit einer Funktion zu machen oder muss ich diese kopieren und unter einem anderen Namen abspeichern?

    Nein. Du kannst einen weiteren Parameter an die Funktion übergeben und anhand deren Wert den Query ändern. Ich setze mal den zweiten parameter als optionalen Parameter, der also wegelassen werden kann udn dann, wenn er eingesetzt wird, den Wert true haben muss.

    function firmen($mysqli, $all = false) {
    
    if ($all === true) {
        $stmt = $mysqli->prepare("SELECT id, code, firma, abteilung, sort, ab_an, signup_an, intern FROM firmen WHERE signup_an = 1 ORDER by sort ASC");
    } else {
        $stmt = $mysqli->prepare("SELECT id, code, firma, abteilung, sort, ab_an, signup_an, intern FROM firmen WHERE signup_an = 1 AND intern = 0 ORDER by sort ASC");
    }
    /* ... weiterer Code ... */
    }
    

    Der Aufruf erfolgt ohne (intern ist dann 0) oder mit dem zweiten Parameter (Wert true), so dass die Abfrage die Spalte intern nicht berücksichtigt.

    Tschö, Auge

    --
    Wenn man ausreichende Vorsichtsmaßnahmen trifft, muss man keine Vorsichtsmaßnahmen mehr treffen.
    Toller Dampf voraus von Terry Pratchett
    1. Ich würde gerne folgende Aspekte genauer beleuchten:

      1. Der Name der Funktion. Sie heißt firmen, liefert aber auch eine Abteilung. Der Name scheint mir nicht 100% passend. Kann natürlich ein Irrtum sein, ist nur so ein Gefühl.

      2. Der Name des Parameters $all. Vermutlich hätte ich ihn $nurExtern genannt, weil sich dann besser erschließt, was passiert.

      3. Die Entscheidung, ihm einen Defaultwert zu geben. Wenn eine von beiden Aufrufvarianten der Ausnahmefall ist und die andere öfter verwendet wird, macht ein Defaultwert Sinn. Oder wenn man schon eine Codebasis hat, die die Funktion an vielen Stellen aufruft, und ich einen Parameter hinzufüge. Andernfalls würde ich keinen Default setzen.

      4. Die Konstruktion des SQL Statements. Ich bin wasserscheu und zucke automatisch zusammen, wenn das DRY[1] Prinzip verletzt wird und die Auswertung solcher Parameter auf eine Auswahl von vollständig ausformulierten SQL Queries führt. Ich erzeuge dann lieber Bausteine für die Query und setze sie am Ende zusammen.

      $externFilter = $all ? "" : "AND intern = 0";
      // oder: $externFilter = $nurExtern ? "AND intern = 0" : "";
      
      $stmt = $mysqli->prepare("SELECT id, code, firma, abteilung, sort, ab_an, signup_an, intern FROM firmen WHERE signup_an = 1 $externFilter ORDER by sort ASC");
      

      Und noch ein Hinweis auf PHP 7: Ab dieser Version kann man die Parametertypen genauer festlegen und so fehlerhafte Übergaben vermeiden:

      function firmen(mysqli $mysqli, bool $all = false) {}
      

      Rolf


      1. Don't Repeat Yourself ↩︎

      1. Hallo

        Ich würde gerne folgende Aspekte genauer beleuchten:

        1. Der Name der Funktion. Sie heißt firmen, liefert aber auch eine Abteilung. Der Name scheint mir nicht 100% passend. Kann natürlich ein Irrtum sein, ist nur so ein Gefühl.

        Ich habe den Namen übernommen, um nicht zusätzlich Verwirrung zu stiften. Aber ja, der Funktionsname ist, gerade wegen der Veränderung des Einsatzzweckes, zumindest überdenkenswert.

        1. Der Name des Parameters $all. Vermutlich hätte ich ihn $nurExtern genannt, weil sich dann besser erschließt, was passiert.

        Soweit ich die Ausgangslage verstehe, geht es um Ergebnisse aus dem interne Bereich gegenüber welchen aus dem internen und externen Bereich. Also eher $nurIntern (true, false).

        1. Die Entscheidung, ihm einen Defaultwert zu geben. Wenn eine von beiden Aufrufvarianten der Ausnahmefall ist und die andere öfter verwendet wird, macht ein Defaultwert Sinn. Oder wenn man schon eine Codebasis hat, die die Funktion an vielen Stellen aufruft, und ich einen Parameter hinzufüge. Andernfalls würde ich keinen Default setzen.

        So weit ich verstanden habe, wird der Code für die Abfrage von Datensätzen aus dem internen Bereich bereits eingesetzt. Wenn ja, würde ich den optionalen Parameter bevorzugen, weil ich die bisherigen Aufrufe der Funktion für die Abfrage von Datensätzen aus dem internen Bereich nicht mehr anfassen müsste. Auch, wenn diese Weise der Abfrage vermutlich den Großteil der Aufrufe ausmacht, würde ich einen optionalen Parameter bevorzugen.

        1. Die Konstruktion des SQL Statements. Ich bin wasserscheu und zucke automatisch zusammen, wenn das [Don't Repeat Yourself] Prinzip verletzt wird und die Auswertung solcher Parameter auf eine Auswahl von vollständig ausformulierten SQL Queries führt. Ich erzeuge dann lieber Bausteine für die Query und setze sie am Ende zusammen.

        Wenn es um meinen eigenen Code ginge, würde ich das auch so handhaben. Zur beispielhaften Gegenüberstellung der Queries, abhängig vom Wert des optionalen Parameters, finde ich meine Schreibweise besser lesbar. Gerade, weil es sich meiner Meinung nach bei Sophie mit einiger Wahrscheinlichkeit um eine Beginnerin in Sachen Programmierung handeln dürfte.

        Und noch ein Hinweis auf PHP 7: Ab dieser Version kann man die Parametertypen genauer festlegen und so fehlerhafte Übergaben vermeiden:

        function firmen(mysqli $mysqli, bool $all = false) {
        }
        

        Gut zu wissen. Danke.

        Tschö, Auge

        --
        Wenn man ausreichende Vorsichtsmaßnahmen trifft, muss man keine Vorsichtsmaßnahmen mehr treffen.
        Toller Dampf voraus von Terry Pratchett
          1. Der Name des Parameters $all. Vermutlich hätte ich ihn $nurExtern genannt, weil sich dann besser erschließt, was passiert.

          Soweit ich die Ausgangslage verstehe, geht es um Ergebnisse aus dem interne Bereich gegenüber welchen aus dem internen und externen Bereich. Also eher $nurIntern (true, false).

          Ätsch ;-), du bist genauso reingefallen wie ich. Mit $nurIntern habe ich auch angefangen. Aber: Die Abfrage im SQL geht auf INTERN=0, das würde ich als Filter auf "nicht Intern" betrachten. Darum bin ich auf $nurExtern umgeschwenkt. Wollte man es auf die MYSQLi-Art machen, definierte man Konstanten wie FIRMEN_ALLE, FIRMEN_INTERN und FIRMEN_EXTERN und verlangt eine von denen :)

          Aber in einem sind wir uns einig: Der Parameter sollte seine Semantik im Namen tragen. $alle ist unklar, weil es nicht aussagt, was $alle=false bewirkt.

          4 . (DRY) (lesbarer für Anfänger)

          Einverstanden. Darum habe ich ja auch "ich würde..." geschrieben. Natürlich ist es anspruchsvoller. Darum habe ich meinen Beitrag bewusst nicht als "Du musst das so machen" eingeleitet, sondern mit dem kleinen Lämpchen :)

          Rolf

          1. Hallo

            Also … $nurIntern (true, false).

            Ätsch ;-), du bist genauso reingefallen wie ich. Mit $nurIntern habe ich auch angefangen. Aber: Die Abfrage im SQL geht auf INTERN=0, das würde ich als Filter auf "nicht Intern" betrachten.

            Der Text des OP ist da etwas unklar. Man könnte meinen, „alle Firmen“ bedeute, dass bisher nur die eigene Firma abgefragt wird. Noch ein Grund mehr, sich mit der Benamsung von Variablen und Funktionen zu beschäftigen. Ich habe mir mittlerweile einen geradezu „geschwätzigen“ Namensstil angewöhnt. Die Variablennamen werden zwar länger und der Quelltext größer, aber ich habe typischerweise auch Monate oder Jahre später noch auf den ersten Blick wenigstens eine Ahnung dessen, was an einer fraglichen Stelle passieren soll, ohne mich gleich durch Kommentare und Dokumentationen (so vorhanden) zu wühlen.

            Tschö, Auge

            --
            Wenn man ausreichende Vorsichtsmaßnahmen trifft, muss man keine Vorsichtsmaßnahmen mehr treffen.
            Toller Dampf voraus von Terry Pratchett
            1. Hello,

              Der Text des OP ist da etwas unklar. Man könnte meinen, „alle Firmen“ bedeute, dass bisher nur die eigene Firma abgefragt wird. Noch ein Grund mehr, sich mit der Benamsung von Variablen und Funktionen zu beschäftigen. Ich habe mir mittlerweile einen geradezu „geschwätzigen“ Namensstil angewöhnt. Die Variablennamen werden zwar länger und der Quelltext größer, aber ich habe typischerweise auch Monate oder Jahre später noch auf den ersten Blick wenigstens eine Ahnung dessen, was an einer fraglichen Stelle passieren soll, ohne mich gleich durch Kommentare und Dokumentationen (so vorhanden) zu wühlen.

              Das stimmt. Darum hatte ich das ja auch vorgeschlagen.
              Und ausführlichere Kommentare, was man sich so gedacht hat, sind auch nicht verkehrt, auch wenn man im Moment der Codeerstellung meint "das sieht man doch". Der kommentar sollte also nicht den Code beschreiben, sondern warum man den Code so geschrieben hat.

              Liebe Grüße
              Tom S.

              --
              Es gibt nichts Gutes, außer man tut es
              Andersdenkende waren noch nie beliebt, aber meistens diejenigen, die die Freiheit vorangebracht haben.
              1. Sorry, hatte ich übersehen.

                Und was viele nicht wissen (oder verdrängen): Man kommentiert und dokumentiert nicht für andere. Sondern für sein eigenes, etwas älteres Selbst. Es wird einem dankbar sein, oder diesen faulen Typen von damals verfluchen...

                Rolf

                1. Hallo

                  Man kommentiert und dokumentiert nicht für andere. Sondern für sein eigenes, etwas älteres Selbst.

                  Njein. MMn kommentiert man „nicht nur für andere“. Zumindest dann, wenn man davon ausgeht, dass der Code auch von anderen angefasst werden können soll.

                  [Das ältere Ich] wird einem dankbar sein, oder diesen faulen Typen von damals verfluchen...

                  Oh ja, das allerdings.

                  Tschö, Auge

                  --
                  Wenn man ausreichende Vorsichtsmaßnahmen trifft, muss man keine Vorsichtsmaßnahmen mehr treffen.
                  Toller Dampf voraus von Terry Pratchett
  3. Tach!

    Ich würde gerne diese Funktion an zwei Stellen verwenden. Soweit kein Problem. Allerdings sollte an der zweiten Stelle, alle Firmen ausgelesen werden, das AND intern = 0 ist demzufolge störend.

    Habe ich die Möglichkeit dieses mit einer Funktion zu machen oder muss ich diese kopieren und unter einem anderen Namen abspeichern?

    Ja klar. Es gibt Funktionsparameter, darüber kann man den Wunsch nach "alle oder nicht" übergeben und es gibt if-Anweisungen, mit denen man das auswerten und das Statement entsprechend zusammensetzen kann.

    dedlfix.

  4. Hello @all,

    mal eine ganz blöde Frage dazu:
    Kann man mit der Bind-Methode eigentlich die Parameter gleich an Elemente eines Arrays binden?

    $_rec = array();
    $stmt->bind_result($_rec['id'], $_rec['code'], $_rec['firma'], $_rec['abteilung'], $_rec['sort'], $_rec['ab_an'], $_rec['signup_an'], $_rec['intern']);
    
    ###... 
    
        while ($stmt->fetch())
        {
            $firmen[] = $rec; 
        }
    

    Liebe Grüße
    Tom S.

    --
    Es gibt nichts Gutes, außer man tut es
    Andersdenkende waren noch nie beliebt, aber meistens diejenigen, die die Freiheit vorangebracht haben.
    1. Tach!

      Kann man mit der Bind-Methode eigentlich die Parameter gleich an Elemente eines Arrays binden?

      Du meinst nicht Parameter (Verwechslungsgefahr mit den Parametern der Query) sondern die Ergebnisfelder. Pinzipiell ja, Array-Elemente sind referenzierbar wie einfache Variablen, und somit erstmal verwendbar. Genauso wie Objekte. Das Problem ist aber,

      $firmen[] = $rec; 
      

      damit erzeugst du nur eine flache Kopie des Arrays. Die Felder in $rec werden durch das bind_result() zu Referenzen auf das was das fetch() liefert und das wird mit jeder Runde überschrieben. In $firmen landen damit jede Menge Referenzen auf die zuletzt gefetchten Werte.

      dedlfix.

      1. Hello,

        $firmen[] = $rec; 
        

        damit erzeugst du nur eine flache Kopie des Arrays. Die Felder in $rec werden durch das bind_result() zu Referenzen auf das was das fetch() liefert und das wird mit jeder Runde überschrieben. In $firmen landen damit jede Menge Referenzen auf die zuletzt gefetchten Werte.

        Ist doch schade. Musste ja einen Pferdefuß geben ;-(

        Liebe Grüße
        Tom S.

        --
        Es gibt nichts Gutes, außer man tut es
        Andersdenkende waren noch nie beliebt, aber meistens diejenigen, die die Freiheit vorangebracht haben.