Ich bekomme einige Fehler, wenn ich versuche, eine dynamische where-Klausel mit mysqli:
zu erstellenWarnung: Parameter 2 für mysqli_stmt :: bind_param () sollte a sein Referenz, Wert angegeben in ... in Zeile 319
Warnung: mysqli_stmt :: execute (): (HY000 / 2031): Keine Daten für geliefert Parameter in vorbereiteter Anweisung in ... in Zeile 328
Warnung: mysqli_stmt :: bind_result (): (HY000 / 2031): Keine Daten bereitgestellt für Parameter in vorbereiteter Anweisung in ... in Zeile 331
Warnung: mysqli_stmt :: store_result (): (HY000 / 2014): Befehle aus synchronisieren; Sie können diesen Befehl jetzt nicht in ... in Zeile 332
ausführen
Ich rate, es gibt eine kleine Änderung, die benötigt wird, um die Probleme zu lösen, aber was passiert, wenn eines der beiden Drop-down-Menüs nicht gleich All
ist oder wenn beide nicht gleich All
sind, dann wird es angezeigt mit den Fehlern.
Unten sehen Sie den Code, der sowohl die Dropdown-Menüs als auch die Abfrage (mit dynamischer where-Klausel) anzeigt, die abhängig von den gewählten Optionen folgt:
HTML:
Studenten Dropdown-Menü:
%Vor%Frage Nummer Dropdown-Menü
%Vor%PHP / MySQL:
%Vor%Hier ist eine DEMO: DEMO
Wählen Sie in der Demo eine Bewertung aus dem Dropdown-Menü und senden Sie sie. Sie werden die zwei Dropdown-Menüs sehen. Halte sie beide als All
und submit, es wird die Abfrage ohne Probleme ausgeben. Nein, ändern Sie All
in einem der Drop-down-Menüs in einen bestimmten Schüler oder eine bestimmte Frage und reichen Sie sie ein. Jetzt sehen Sie die Fehler
VAR DUMP:
Das Ergebnis von var_dump(array_merge(array($parameterTypes), $parameters)));
, wenn ich Sitzung (Assessment) mit Wert 31
, Schülernummer Wert 40
und Frage Nummer Wert 81
und WHERE CLAUSE WHERE q.SessionId = ? AND sa.StudentId = ? AND q.QuestionId = ?
:
Ich bekomme diese Ausgabe: array(4) { [0]=> string(3) "iii" [1]=> string(2) "31" [2]=> string(2) "40" [3]=> string(2) "81" }
Dies ist eine klebrige Situation, die durch die Änderung von call_user_func_array
Verhalten in PHP 5.4 verursacht wird (ich muss annehmen): Dokumentation
So hässlich das ist, wird es funktionieren, bind_param
auf diese Weise aufzurufen:
Ich hasse das so sehr, wie Sie wahrscheinlich tun. Ich schlage vor, von mysqli
zu PDO
zu wechseln, das variable Parameter viel besser verarbeitet (und meiner Meinung nach eine bessere Syntax hat):
Warnung: Parameter 2 für mysqli_stmt :: bind_param () sollte eine Referenz sein, Wert in ... in Zeile 319
Dies sollte selbsterklärend sein: Die Argumente von bind_param werden als Referenz übergeben und müssen daher Variablen sein. Was Sie vielleicht übersehen haben, ist, dass array_merge
ein neues Array zurückgibt, das keine Verweise auf die ursprünglichen Variablen enthält, sondern nur Werte.
Die folgenden Fehler sind unmittelbar danach, weil die Parameter nicht gebunden waren.
Eine mögliche Lösung ist, Referenzen in Ihrem $parameters
-Array zu speichern, diese werden sogar von array_merge beibehalten:
Nun sind die Array-Elemente von $parameters
Verweise auf POST-Variablen und die Array-Elemente von array_merge
ebenfalls.
Bearbeiten: sieht so aus, als ob das nicht mehr möglich ist, siehe @Explosionspillen
Das ist immer noch nicht genug, um mysqli für PDO abzulehnen, besonders wenn ich damals sehr gute Gründe hatte, PDO nicht zu benutzen. Auf der anderen Seite, ja, sie mussten die Methoden mysqli_stmt :: bind_param und bind_result nicht erzwingen, um zu verlangen, dass die Variablen vonRef übergeben wurden, sie konnten sie ein Array zurückgeben lassen. Das eigentliche Problem hierbei ist, dass Call-Time-Pass-by-Reference nicht mehr möglich ist, aber mysqli immer noch Pass-by-Reference benötigt, so dass jeder, der dynamische Parameter verwendet (jemand mit intuitivem SQL), gefangen wird in dieser Ausgabe, mich eingeschlossen. Nachdem ich Stunden damit verbracht habe, eine benutzerdefinierte mysqli-Wrapper-Klasse zu schreiben, die Array-Sets in dynamisch vorbereitete SQL-Anweisungen konvertiert, werde ich nicht versuchen, alles neu zu schreiben, um mit PDO zu arbeiten, besonders da PDO die Parameter als Teil der Bindung benennen muss. Ich müsste mehrere Funktionen schreiben, um die Liste dessen, was gesendet wurde, für jeden Abfragetyp zu erstellen. Das ist kontraintuitiv, und ich werde nicht unzählige Stunden damit verschwenden, das nachzuahmen, was ich mit mysqli erreicht habe.
Die einzige Schwierigkeit an diesem Punkt ist, dass wir die Variablen in call_user_func_array () byRef nicht übergeben können und dass mysqli_stmt :: bind_ * verlangt, dass sie vonRef ... übergeben werden. Die einzigen Optionen sind 1) schreibe ein neues call_user_func_array () - Funktion, die explizit für die Methoden bind_ * entworfen wurde, wobei die übergebenen Parameter im Wesentlichen in ein neues Array oder eine Gruppe von Variablen mit args kopiert werden und dann byRef beim Callback übergeben werden; oder 2) schreibe die mysqli-Klasse neu, um es richtig zu machen, und schaue einfach, was passiert ist, führe die SQL aus und gebe das Ergebnis wie vorgesehen zurück. Es gibt keinen Grund, dass das, was wir an eine Methode übergeben, um SQL auszuführen, mit Ergebnissen durcheinander gebracht werden muss, es sollte genauso behandelt werden wie eine SQL-Konsole.
Da ich vom Codieren viel zu erschöpft bin, bis meine Augen fast bluten, werde ich die nicht vorgeschlagene Option nehmen, meine PHP-Version bei 5.3.10-1 festzuhalten, bis ich das Problem tatsächlich richtig gelöst habe. Für diejenigen, die argumentieren "für all diese Bemühungen, warum nicht einfach nur für das Schreiben Ihres PDO-Wrappers?" ... und meine Antwort ist einfach: Ich benutze PHP und MySQL ausschließlich für viele Projekte, bei denen der Server ein winziger kleiner Computer ist mit sehr begrenztem Raum und Ressourcen, ganz zu schweigen von der CPU-Fähigkeit. PDO lädt ALLES, was es tun kann, nicht nur das, was Sie verwenden werden, daher gibt es in Ihren Ressourcen einige Vorbehalte für Dinge, die Sie nicht einmal nutzen werden, die meine Projekte nicht verlieren können.
Zum Glück wird es nicht schädlich sein, meine PHP-Version zurückzuhalten. Das ist es, was viele Serverfarmen auf Unternehmensebene tun, um zu vermeiden, dass alles heruntergefahren werden muss, um "auf der aktuellen Version" von etwas zu sein, was auch unglaublich teuer ist, alle paar Jahre zu aktualisieren.