Jnnbo: Funktion mehrfach verwenden

Hallo,

wenn ich es richtig verstehe, dann sind Funktionen dafür da um weniger Arbeit zu haben richtig? Also müsste es doch möglich sein meine Funktion die derzeit so aussieht:


	function admin_Benefits($mysqli) {
		$stmt = $mysqli->prepare("SELECT b_id, b_projekt, b_titel, b_bild, b_video, b_beschreibung, b_anzahl, b_preis, b_status, p_titel FROM benefits LEFT JOIN projekte ON projekte.p_id = benefits.b_projekt");
		$stmt->execute();
		$stmt->bind_result($b_id, $b_projekt, $b_titel, $b_bild, $b_video, $b_beschreibung, $b_anzahl, $b_preis, $b_status, $p_titel);
	 	$stmt->store_result();
	 	
		if($stmt->num_rows() >  0) {
			while ($stmt->fetch()){
				
				$admin_Benefits[] = array(
					'b_id' 				=> $b_id,
					'b_projekt' 		=> $b_projekt,
					'b_titel' 			=> $b_titel,
					'b_bild' 			=> $b_bild,					
					'b_video' 			=> $b_video,
					'b_beschreibung' 	=> $b_beschreibung,
					'b_anzahl' 			=> $b_anzahl,
					'b_preis' 			=> $b_preis,
					'b_preis' 			=> $b_preis,
					'b_status' 			=> $b_status,
					'p_titel' 			=> $p_titel
				);
			}
			return $admin_Benefits;
			}
	}

etwas zu ändern dass ich auch ein WHERE mit übergeben kann. Z.B. möchte ich alle Einträge haben die zu einer bestimmten ID passen, auf einer Unterseite benötige ich allerdings alle Einträge. Ist dieses möglich oder soll ich einfach die Funktion duplizieren?

  1. Tach!

    Also müsste es doch möglich sein meine Funktion [...] etwas zu ändern dass ich auch ein WHERE mit übergeben kann. [...] Ist dieses möglich oder soll ich einfach die Funktion duplizieren?

    Ja, das ist möglich. Was ist dein Problem dabei?

    dedlfix.

    1. Hallo,

      Ja, das ist möglich. Was ist dein Problem dabei?

      das heißt also, ich muss meiner Funktion ein Wert übergeben, dieses mache ich so

      
      function admin_Benefits($mysqli, $id) {
      $stmt = $mysqli->prepare("SELECT b_id, b_projekt, b_titel, b_bild, b_video, b_beschreibung, b_anzahl, b_preis, b_status, p_titel FROM benefits LEFT JOIN projekte ON projekte.p_id = benefits.b_projekt WHERE b_titel = ? ");
      $stmt->bind_param("s", $id);
      
      

      bin ich da auf dem richtigen Weg? Und was passiert, wenn der $id leer bleibt?

      1. Moin!

        bin ich da auf dem richtigen Weg? Und was passiert, wenn der $id leer bleibt?

        Das kannst Du in meiner Antwort von 14:10 nachsehen.

        Jörg Reinholz

        1. Hallo Jörg,

          Das kannst Du in meiner Antwort von 14:10 nachsehen.

          danke für deine Antwort, deine Antwort von 14:10 Uhr habe ich gelesen und schau wie ich das nun umsetzten kann.

          1. Das kannst Du in meiner Antwort von 14:10 nachsehen.

            An dieser Antwort ist hilfreich, dass Du optionale Parameter einführst. Nicht so ansehnlich finde (ich persönlich) das if(){}else{} Konstrukt.

            Cheers, Baba

            --
            Baba kommt von Basketball
            1. Hallo,

              An dieser Antwort ist hilfreich, dass Du optionale Parameter einführst.

              Wie du es beschrieben hast?

              Nicht so ansehnlich finde (ich persönlich) das if(){}else{} Konstrukt.

              Wie würdest du es dann ohne if(){}else{} machen? Ich benötige ja die Unterscheidungen?

              1. Wie du es beschrieben hast?

                Ja, auch ich verwende optionale Parameter (Parameter, die in der Funktion mit = "defaultWert" deklariert werden).

                Wie würdest du es dann ohne if(){}else{} machen? Ich benötige ja die Unterscheidungen?

                Nun ich würde nicht zwei unterschiedliche Codes produzieren, die im If/else Block ausgeführt werden, da dies viel doppelten Code erzeugt. Vielmehr würde ich Variablen per if/else zuweisen. Ich benutze dafür gerne den ternary operator:

                if($bedingung){
                  $val = 3;
                } else {
                  $val = 6;
                }
                

                ist gleich bedeutend mit

                $val = $bedingung ? 3 : 6;
                
                

                Cheers, Baba

                --
                Baba kommt von Basketball
                1. Tach!

                  Wie würdest du es dann ohne if(){}else{} machen? Ich benötige ja die Unterscheidungen? Nun ich würde nicht zwei unterschiedliche Codes produzieren, die im If/else Block ausgeführt werden, da dies viel doppelten Code erzeugt. Vielmehr würde ich Variablen per if/else zuweisen. Ich benutze dafür gerne den ternary operator:

                  Wie formulierst du denn mit dem ternary operator die beiden Fälle "alle Datensätze" und "einen bestimmmten"?

                  dedlfix.

                  1. Wie formulierst du denn mit dem ternary operator die beiden Fälle "alle Datensätze" und "einen bestimmmten"?

                    Siehe :

                    $where  = $where ? "WHERE b_projekt = $where" : "";
                    $query  = "SELECT $select FROM $from $where $join";
                    

                    Cheers, Baba

                    --
                    Baba kommt von Basketball
                    1. Tach!

                      Wie formulierst du denn mit dem ternary operator die beiden Fälle "alle Datensätze" und "einen bestimmmten"? Siehe :

                      $where  = $where ? "WHERE b_projekt = $where" : "";
                      
                      > $query  = "SELECT $select FROM $from $where $join";
                      
                      

                      Das geht so nicht, weil du das Prepared Statement unberücksichtigt lässt und den Wert direkt und auch noch ohne weitere Absicherungen in das Statement einbaust.

                      dedlfix.

                      1. Das geht so nicht, weil du das Prepared Statement unberücksichtigt lässt

                        Ich lasse das Prepared Statement nicht unberücksichtigt. Schau doch mal bitte.

                        und den Wert direkt und auch noch ohne weitere Absicherungen in das Statement einbaust.

                        die Absicherungen kann man ja gerade hier noch einfach einbauen.

                        Cheers, BaBa

                        --
                        BaBa kommt von Basketball
                        1. Tach!

                          Das geht so nicht, weil du das Prepared Statement unberücksichtigt lässt

                          Ich lasse das Prepared Statement nicht unberücksichtigt. Schau doch mal bitte.

                          Doch, doch. Du verwendest es zwar, ignorierst aber seine wichtigste Eingenschaft, dass man Parameter über einen Platzhalter angibt und den eigentlichen Wert in einem weiteren Schritt bindet. Wenn du das so machst, geht der ternäre Operator nicht, weil das bind() ebenfalls bedingt ausgeführt werden muss. Also, das geht schon mit dem ?:, aber das wird nicht übersichtlicher.

                          und den Wert direkt und auch noch ohne weitere Absicherungen in das Statement einbaust.

                          die Absicherungen kann man ja gerade hier noch einfach einbauen.

                          Das müsste man nicht, wenn man es gleich richtig macht.

                          dedlfix.

                          1. Doch, doch. Du verwendest es zwar, ignorierst aber seine wichtigste Eingenschaft, dass man Parameter über einen Platzhalter angibt und den eigentlichen Wert in einem weiteren Schritt bindet.

                            Jetzt habe ich Dich! Danke :)

                            Cheers, BaBa

                            --
                            BaBa kommt von Basketball
      2. Tach!

        das heißt also, ich muss meiner Funktion ein Wert übergeben, dieses mache ich so function admin_Benefits($mysqli, $id) {

        Du willst doch mal was übergeben und mal nicht. Dann musst du $id optional machen, sprich: einen Defaultwert setzen, der sich von allen wirklichen Werten unterscheidet, beispielsweise null.

        bin ich da auf dem richtigen Weg? Und was passiert, wenn der $id leer bleibt?

        Dann werden keine Daten gefunden. Du darfst den WHERE-Teil erst anfügen, wenn du weißt, dass $id einen sinnvollen Wert enthält und nicht den Defaultwert. Das Bind gibts dann auch erst in dem Fall.

        dedlfix.

  2. Moin!

    wenn ich es richtig verstehe, dann sind Funktionen dafür da um weniger Arbeit zu haben richtig? Also müsste es doch möglich sein meine Funktion die derzeit so aussieht:

    Wie wäre es denn damit?

    
    function admin_Benefits($mysqli, $where=false) {
      if ($where) {
         # Tu was
      } else {
         # Du nicht
      }
         # lassen kannst
    ]
    
    

    Aufruf z.B. mit

    • admin_Benefits($mysqli);
    • admin_Benefits($mysqli, 'foo="bar"');

    Jörg Reinholz

    1. Tach!

      Aufruf z.B. mit

      • admin_Benefits($mysqli);
      • admin_Benefits($mysqli, 'foo="bar"');

      Na so nicht unbedingt. Da entgehen Jnnbo ja die Vorteile von Prepared Statements. Werte besser als Wert übergeben. Solange es nur eine ID ist, ist es einfach, diese direkt zu übergeben. Sollen die Felder flexibel sein, dann eignet sich ein assoziatives Array. Allerdings hat man dann ein Problem, diese Werte für PHPs mysqli-Bind-Mechanismus aufzubereiten.

      dedlfix.

      1. Hallo,

        Na so nicht unbedingt. Da entgehen Jnnbo ja die Vorteile von Prepared Statements. Werte besser als Wert übergeben. Solange es nur eine ID ist, ist es einfach, diese direkt zu übergeben.

        das heißt also, ich soll so nicht vorgehen wie Jörg es mir gezeigt hat?

        1. Tach!

          Na so nicht unbedingt. Da entgehen Jnnbo ja die Vorteile von Prepared Statements. Werte besser als Wert übergeben. Solange es nur eine ID ist, ist es einfach, diese direkt zu übergeben. das heißt also, ich soll so nicht vorgehen wie Jörg es mir gezeigt hat?

          Doch, aber nur teilweise. Nur die Werte übergeben und keine halben Statements. Die aufrufende Stelle muss keine Ahnung von MySQL-Syntax haben.

          dedlfix.

          1. Hallo,

            Doch, aber nur teilweise. Nur die Werte übergeben und keine halben Statements. Die aufrufende Stelle muss keine Ahnung von MySQL-Syntax haben.

            ok, ich habe es nun so umgesetzt, es funktioniert. Hoffentlich habe ich euch richtig verstanden:

            Der Aufruf meiner Funktion mit Parameter

            
            $admin_Benefits = admin_Benefits($mysqli, "1");
            
            

            und ohne Parameter

            
            $admin_Benefits = admin_Benefits($mysqli);
            
            

            Die Funktion selber dann so:

            
            function admin_Benefits($mysqli, $id=false) {
            	if ($id) {
            		$stmt = $mysqli->prepare("SELECT b_id, b_projekt, b_titel, b_bild, b_video, b_beschreibung, b_anzahl, b_preis, b_status, p_titel FROM benefits LEFT JOIN projekte ON projekte.p_id = benefits.b_projekt WHERE b_projekt = ? ");
            		$stmt->bind_param("s", $id);
              		} else {
            		$stmt = $mysqli->prepare("SELECT b_id, b_projekt, b_titel, b_bild, b_video, b_beschreibung, b_anzahl, b_preis, b_status, p_titel FROM benefits LEFT JOIN projekte ON projekte.p_id = benefits.b_projekt ");
            		}
            $stmt->execute();
            
            
            1. Tach!

              Hoffentlich habe ich euch richtig verstanden:

              Ja, aber: Don't repeat yourself! Den String der Query kannst du bis auf den WHERE-Teil in einer Variable ablegen (vor dem if ($id)). Für den einen Fall nimmst du dann die Variable, für den anderen die Variable zuzüglich WHERE-Teil.

              dedlfix.

              1. Hallo,

                Ja, aber: Don't repeat yourself! Den String der Query kannst du bis auf den WHERE-Teil in einer Variable ablegen (vor dem if ($id)). Für den einen Fall nimmst du dann die Variable, für den anderen die Variable zuzüglich WHERE-Teil.

                wenn ich dich richtig verstanden habe, dann sollte es so aussehen?

                
                	function admin_Benefits($mysqli, $id=false) {
                		
                		$select = "SELECT b_id, b_projekt, b_titel, b_bild, b_video, b_beschreibung, b_anzahl, b_preis, b_status, p_titel FROM benefits LEFT JOIN projekte ON projekte.p_id = benefits.b_projekt ";
                		
                		if ($id) {
                			$stmt = $mysqli->prepare("$select WHERE b_projekt = ? ");
                			$stmt->bind_param("s", $id);
                  		} else {
                			$stmt = $mysqli->prepare("$select");
                		}
                		$stmt->execute();
                
                
                1. Tach!

                  wenn ich dich richtig verstanden habe, dann sollte es so aussehen? $stmt = $mysqli->prepare("$select WHERE b_projekt = ? "); $stmt = $mysqli->prepare("$select");

                  Ja, aber: Es ist unsinnig, eine Variable allein in doppelte Anführungszeichen zu setzen. Das Ergebnis ist dasselbe wie ohne Anführungszeichen, nur etwas umständlicher. Und in der ersten Zeile würde ich auch lieber Stringverküpfung nehmen, statt die Variable einzubetten: $select . " WHERE b_projekt = ? "

                  dedlfix.

                  1. Hallo,

                    Ja, aber: Es ist unsinnig, eine Variable allein in doppelte Anführungszeichen zu setzen. Das Ergebnis ist dasselbe wie ohne Anführungszeichen, nur etwas umständlicher. Und in der ersten Zeile würde ich auch lieber Stringverküpfung nehmen, statt die Variable einzubetten: $select . " WHERE b_projekt = ? "

                    ok, hab ich auch angepasst:

                    
                    if ($id) {
                    	$stmt = $mysqli->prepare($select . "WHERE b_projekt = ?" );
                    	$stmt->bind_param("s", $id);
                      	} else {
                    	   $stmt = $mysqli->prepare($select);
                    	}
                    
                    
                  2. Hallo,

                    habe mich nun an die Ausgabe meiner Daten gemacht, dieses habe ich so umgesetzt:

                    
                    <?php
                    $Benefits = admin_Benefits($mysqli, $object->p_id);
                    if($Benefits > 0) {?>
                    <h3>Benefits</h3>
                    <?php
                    foreach($Benefits as $ausgabe){?>
                    <p>(<?php echo htmlspecialchars($ausgabe['p_titel']); ?>)</p>
                    <?php
                    }}
                    ?>
                    
                    

                    Bin ich auf dem richtigen Weg, oder würdet du dieses anderes umsetzten?

                    1. Tach!

                      $Benefits = admin_Benefits($mysqli, $object->p_id); if($Benefits > 0) {?>

                      Ist $Benefits eine Zahl?

                      foreach($Benefits as $ausgabe){?>

                      Nein, ein Array. PHP ist zwar gutmütig und konvertiert Typen. Besser ist es aber, die Intention dahinter deutlicher zu formulieren

                      if (count($Benefits) > 0)

                      dedlfix.

                2. Hallo Jnnbo,

                  du sprichst ein wichtiges Thema an. Funktionen so zu schreiben, dass sie a) keine reduntanten (doppelten) Code enthalten und b) für andere, ähnliche Zwecke gebraucht werden können, ist ein wesentliches Qualitätsmerkmal für Programmcode. Mmn ist dies etwas, was ein jeder über die Jahre stetig verbessert.

                  Vorstellbar wäre auch so etwas...

                  function admin_Benefits($mysqli, $select, $from, $where=false) {
                  
                      $select = implode(",", $select);
                      $where  = $where ? "WHERE b_projekt = $where" : "";
                      $join   = "LEFT JOIN projekte ON projekte.p_id = benefits.b_projekt";
                      $query  = "SELECT $select FROM $from $where $join";
                  
                      $stmt = $mysqli->prepare($query);
                      $stmt->execute();
                  
                      #(...)
                  
                  

                  Aufrufen mit

                  admin_Benefits(
                    $mysqli,
                    array("b_id", "b_projekt", "b_titel", "b_bild", "b_video", "b_beschreibung"),
                    "benefits",
                    "bestimmteid_optional"
                  );
                  
                  

                  So hast Du zum Beispiel die Funktion auch variabel für den Fall, das zu in einer anderen Tabelle etwas abfragst oder dass Du andere Werte bekommen möchtest. Auch könnte man sich noch überlegen den Join per optionalem Parameter zu steuern. Auch sparst Du so einmal die Zeile ->prepare in Deinem Code.

                  Zur Diskussion gestellt...

                  Cheers, Baba

                  --
                  Baba kommt von Basketball
                  1. Moin Baba,

                    Vorstellbar wäre auch so etwas... […]

                    Da solltest du direkt über ein ORM nachdenken. Da kann man das viel schöner lösen, in Rails ist z.B. das hier ein von mir häufig eingesetztes Feature:

                    
                    @threads = CfThread.where(forum_id: current_forum.forum_id)
                    unless current_user.root?
                      @threads = @threads.where(deleted: false)
                    end
                    
                    @threads = standard_permissions(@threads)
                    @threads = @threads.order('created_at DESC').all
                    
                    

                    standard_permissions verändert das Query-Objekt dann nochmal, indem es einen eager load hinzufügt und auf Zugriffsrechte prüft:

                    
                    def standard_permissions(query)
                      return query.preload(:forum).where("EXISTS(SELECT user_id FROM forum_permissions WHERE permission = 'read' AND user_id = ?)", current_user.user_id)
                    end
                    
                    

                    Solche ORMs gibt es auch für PHP, z.B. Doctrine.

                    LG,  CK

                    P.S.: Disclaimer: das ist nicht der wirklich verwendete Code, nur das Schema wie ich das handhabe ;)