.MB: PHP SQL Statements

Hallo Community,

z.Z. arbeite ich an SQl Statements. Ein kleines Beispiel veranschaulicht gut meine Frage

$sql = "INESRT INTO {$tabelle} ( {$spalte1}, {$spalte2}, ... ) VALUE ( {$value1}, {$value2}, ... );"

Compakt, gut aber ich schätze mal weniger perfomant

$sql = 'INESRT INTO ' .$tabelle. ' ( ' .$spalte1. ', ' .$spalte2. ', ... ) VALUE ( ' .$value1. ', ' .$value2. ', ... );'

idiotisch lang aber ich schätze mal perfomater.

Ich bräuchte hilfe bei der wahl.

vlg MB

PS: Die Klassen habe ich sehr abstrakt gemacht.

  1. Hallo MB,

    z.Z. arbeite ich an SQl Statements. Ein kleines Beispiel veranschaulicht gut meine Frage

    $sql = "INESRT INTO {$tabelle} ( {$spalte1}, {$spalte2}, ... ) VALUE ( {$value1}, {$value2}, ... );"
    

    Compakt, gut aber ich schätze mal weniger perfomant

    $sql = 'INESRT INTO ' .$tabelle. ' ( ' .$spalte1. ', ' .$spalte2. ', ... ) VALUE ( ' .$value1. ', ' .$value2. ', ... );'
    

    idiotisch lang aber ich schätze mal perfomater.

    Ich bräuchte hilfe bei der wahl.

    Im besten Fall nimmst Du wohl keine der beiden Varianten:

    1. Stringverkettungen sind meistens schlecht lesbar. Wenn Du eh objektorientiert arbeitest, dann schreibe Dir Klassen, welche diese Verkettungen übernehmen können.
    2. Beachte immer den Kontextwechsel. Selbst dann, wenn Du Dir sicher bist, wo die Daten herkommen (Fehler können immer mal irgendwo, insbes. zukünftig, passieren, deswegen lieber von Anfang an beachten).
    3. Wenn beide Varianten tatsächlich einen Performance-Unterschied machen sollten, wäre er vermutlich vernachlässigbar klein. Nehme die Variante, die am besten lesbar und am wenigsten fehleranfällig ist. Wenn Du irgendwo Performance-Probleme entdeckst, liegt es mit Sicherheit nicht am Unterschied dieser beiden Varianten. Außerdem kannst Du Dich dann zielgerichtet auf die Suche begeben. Sowas im Voraus einzuplanen ist in aller Regel unnötig und nicht zielführend.
    4. Verwende so etwas wie PDO, damit hast Du einige der zuvor genannten Probleme bereits erschlagen.

    Ansonsten noch zu Deiner Frage, was performanter ist: Das wirst Du nur durch echte Analyse eines aussagekräftigen Tests herausbekommen. Zum einen spielen da unglaublich viele Faktoren eine Rolle. Zum anderen kommt es in diesem speziellen Fall sicherlich noch zusätzlich darauf an, wie viele Variablen "ersetzt" werden müssen. Dass der zweite Fall performanter ist, ist reine Spekulation. Es könnte durchaus auch anders herum oder abhängig von der Anzahl der Variablen sein.

    Gruß
    Dennis

    1. Abend Dennis,

      Im besten Fall nimmst Du wohl keine der beiden Varianten:

      1. Stringverkettungen sind meistens schlecht lesbar. Wenn Du eh objektorientiert arbeitest, dann schreibe Dir Klassen, welche diese Verkettungen übernehmen können.

      Ok jetzt steh ich auf dem Schlauch. Was meinst du mit String-Verkettung über Klassen?

      1. Verwende so etwas wie PDO, damit hast Du einige der zuvor genannten Probleme bereits erschlagen.

      Jo ich arbeite nur mit PDO

      Besten dank für deine AW

      vlg MB

      1. Hallo,

        Jo ich arbeite nur mit PDO

        Wieso habe ich das Gefühl, dass dein "sql = ..." so gar nix mit PDO zu tun hat?

        Gruß
        Kalk

      2. Hallo MB,

        Im besten Fall nimmst Du wohl keine der beiden Varianten:

        1. Stringverkettungen sind meistens schlecht lesbar. Wenn Du eh objektorientiert arbeitest, dann schreibe Dir Klassen, welche diese Verkettungen übernehmen können.

        Ok jetzt steh ich auf dem Schlauch. Was meinst du mit String-Verkettung über Klassen?

        kann ich verstehen, dass Du auf dem Schlauch stehst. Da hab ich mich ziemlich blöd ausgedrückt. Sorry.

        Ohne Stringverkettung geht es natürlich nicht. Es gibt nur Möglichkeiten, dass Du das komplette SQL-Statement mit Hilfe von Methoden einer Klasse zusammen baust. Das ist zwar immer noch eine Verkettung von Strings, aber deutlich übersichtlicher, weil die Verkettung an sich oft nur wenige kurze Strings zusammensetzt. Von außen betrachtet erkennt man dann die interne Funktionsweise nicht mehr. Vielmehr ruft man dann Methoden wie

        $sql->select()->from(...)->where(...)->order(...)
        

        auf. Einige Frameworks machen das so mit Hilfe eines zusätzlichen Layers. Ob man das braucht, sei dahingestellt. Es erleichtert einem aber oft die Arbeit, wenn man sich nicht immer um die gleichen Dinge wie Kontextbehandlung kümmern muss. Wenn Dich das interessiert, schau Dir mal aktuelle Frameworks an und wie die das machen.

        Unabhängig davon macht PDO schon einiges von dem. Das ist ja auch sowas wie ein zwischengeschalteter Layer.

        1. Verwende so etwas wie PDO, damit hast Du einige der zuvor genannten Probleme bereits erschlagen.

        Jo ich arbeite nur mit PDO

        Ok, das ist schon mal gut. Kennst Du denn die verschiedenen bind()-Funktionen von PDO? Wenn ja, bräuchtest Du Dir Deine ursprüngliche Frage nicht stellen, da Du dann Platzhalter (ähnlich Deiner ersten Variante) verwenden würdest.

        Klar ist aber, dass eine zusätzliche "Schicht" wie PDO immer etwas langsamer sein wird. Das ist im normalen Betrieb aber kein Problem.

        Falls was unklar ist, frag einfach nach.

        Gruß
        Dennis

        1. $sql->select()->from(...)->where(...)->order(...)
          

          Echt jetzt? Entweder brauche ich dann ein ziemlich komplexes Framework, oder ich kann nur ein mageres SQL Subset erzeugen. Und am SQL Wissen komme ich trotzdem nicht vorbei.

          Ein ORM Framework generiert mir SQL an Hand meiner Zugriffe (was auch nur in simplen Fällen optimal gelingt). Dem sage ich nichts von SELECT und FROM und WHERE. Das ist das Rohrleitungssystem unter dem Fußboden. Für das CRUD Geschäft ist es meist hinreichend.

          Bei komplizierteren Auskunfts-Queries, die maßgeschneiderte Viewmodels für Informationsseiten erzeugen, komme ICH zumindest selten um Handarbeit drumherum. Würde ich die per Framework holen, müsste ich viel zu viele Daten lesen und dann selbst im RAM zusammen bauen. Aber vielleicht bin ich ja auch zu sehr 1990 dafür (was man an dem HTML sieht was ich zusammenbaue...).

          Rolf

          1. Hallo Rolf,

            $sql->select()->from(...)->where(...)->order(...)
            

            Echt jetzt? Entweder brauche ich dann ein ziemlich komplexes Framework, oder ich kann nur ein mageres SQL Subset erzeugen. Und am SQL Wissen komme ich trotzdem nicht vorbei.

            vollkommen richtig. Ist nen schlecht gewähltes Beispiel, anhand dessen ich das "wegkapseln" von so ner Funktionalität zeigen wollte. Hatte auch erst noch überlegt, ob ich das überhaupt schreiben sollte. Hätte ich wohl besser weg gelassen.

            Ein ORM Framework generiert mir SQL an Hand meiner Zugriffe (was auch nur in simplen Fällen optimal gelingt). Dem sage ich nichts von SELECT und FROM und WHERE. Das ist das Rohrleitungssystem unter dem Fußboden. Für das CRUD Geschäft ist es meist hinreichend.

            Aber hier bringst Du mit ORM das passende Stichwort. Darauf wollte ich hinaus, hatte nur eine Stufe darunter ansetzen wollen. Also da, was das Grundprinzip des ORM o.ä. ist.

            Aber vielleicht bin ich ja auch zu sehr 1990 dafür (was man an dem HTML sieht was ich zusammenbaue...).

            Zumindest in dem Fall hier denke ich nicht :-)

            Gruß
            Dennis

    2. Tach!

      2. Beachte immer den Kontextwechsel. Selbst dann, wenn Du Dir sicher bist, wo die Daten herkommen (Fehler können immer mal irgendwo, insbes. zukünftig, passieren, deswegen lieber von Anfang an beachten).

      Die Herkunft der Daten ist belanglos. Auch aus "sicheren Quellen" können Daten kommen, in denen Zeichen mit besonderer Bedeutung aus der Sicht eines SQL-Statements enthalten sind. Anführungszeichen sind zum Beispiel nicht nur Zeichen, mit denen SQL-Injections beabsichtigt werden. Kontextwechselbeachtung ist keine optionale Sicherheitsveranstaltung sondern eine generelle Notwendigkeit, um syntaktisch korrekte Ergebnisse zu erzielen.

      4. Verwende so etwas wie PDO, damit hast Du einige der zuvor genannten Probleme bereits erschlagen.

      Ja, aber nicht einfach nur so, sondern Querys mit variablen Werten als Prepared Statement schreiben. Das hat möglicherweise eine noch schlechtere Performance, weil für das vorbereitete Statement und die Ausführung mit Übertragen der Werte zwei Roundtrips zum SQL-Server notwendig sind, aber das in Kauf zu nehmen ist deutlich besser als Statements mit maskierten Werten zusammenzustückeln. "Schlechtere Peformance" heißt in dem Fall aber auch nicht, dass der Anwender eine Verzögerung wahrnimmt.

      dedlfix.

      1. Hallo dedlfix,

        danke für die weiteren Ausführungen. Das ist das, was ich eigentlich sagen wollte. Wie schon die Antwort an Rolf zeigt, muss ich nach so langer (zumindest schreibender) Forenabstinenz wohl meine Erkläransätze neu kalibrieren.

        Gruß
        Dennis

  2. Ob Du nun die Strings manuell verkettest oder den Stringparser von PHP nutzt, macht sicher wenig Unterschied. Ich traue dem Burschen sogar zu, dass er die Variablenreferenzen in deinem ersten Beispiel im Stringliteral erkennt und automagisch zur Concatenation compiliert.

    Ein Massen-Insert wird hier aber nicht die Zeit verlieren. Die Wartezeit auf den SQL-Server ist um Größenordnungen länger. Unter diesem Aspekt ist es komplett egal, wie du das SQL aufbaust.

    Viel wichtiger ist aber dies: Was Du da vorlegst, solltest Du so keinesfalls tun.

    Es ist obsolet, veraltet, oder deprecated, kann man nennen wie man will. Man baut kein SQL mit Daten zusammen, wenn es sich vermeiden lässt! Unvermeidbar war es mit der mysql-Extension von PHP, aber mit mysqli oder PDO hast Du die Möglichkeit, prepared statements zu nutzen und SQL-Parameter zu definieren. Pro INSERT änderst Du dann lediglich die Parameterwerte und schickst das gleiche Statement nochmal los. Um Altlasten wie Parameter-Escaping brauchst Du Dich dann auch nicht zu kümmern, das erledigt der SQL Treiber für Dich.

    Schau es Dir in der PHP Doku mal an. MYSQLI verwendet Fragezeichen als Parametermarker, da musst Du dann aufpassen wie Du die Parameter zuordnest. PDO kennt benannte Parameter. Was NICHT geht, sind Tabellen- und Spaltennamen als SQL Parameter (zumindest nicht unter MS SQL Server, mit dem ich arbeite). D.h. den strukturellen SQL Teil wirst Du Dir nach wie vor zur Laufzeit konstruieren müssen, wenn Du aus prinzipiellen Gründen kein statisches SQL nutzen kannst. Aber die Inhalte gehören in SQL Parameter.

    Falls Du Dir ein ORM Framework zusammenbastelst: Kann man machen, muss man aber nicht. Dafür gibt's fertige Lösungen. Die cachen dann auch ihre prepared Statements und erzeugen sie nicht für jeden INSERT oder UPDATE neu, was die Frage nach der Effizienz der SQL Generierung komplett obsolet macht...

    Rolf

    1. Ich arbeite natürlich mit specialhtmlchars() und Prepared statements. Das hatte ich nicht angeführt Sry

      1. Hi,

        Ich arbeite natürlich mit specialhtmlchars() und Prepared statements.

        Und was soll specialhtmlchars beim Zusammenbau eines SQL-Statements bewirken (außer daß es die Daten kaputtmacht)?

        cu,
        Andreas a/k/a MudGuard

      2. Hallo MB,

        Ich arbeite natürlich mit specialhtmlchars() und Prepared statements. Das hatte ich nicht angeführt Sry

        Prepared statements sind keine Magie, deine String-Concatenations werden nicht magisch dadurch sicher, dass du sie durch pepare() jagst. Du musst das schon richtig anwenden. Statt

        $sql = "INESRT INTO {$tabelle} ( {$spalte1}, {$spalte2}, ... ) VALUE ( {$value1}, {$value2}, ... );"

        lieber Platzhalter verwenden, etwa so:

        $sth = $db->prepare("INSERT INTO tablename (col1, col2, ...) VALUES (:col1, :col2, ...)");
        $sth->execute(array(':col1' => $value1, ':col2' => $value2));
        

        Nur so kannst du sichergehen, dass keine SQL-Injection stattfindet.

        LG,
        CK

        1. Hallo CK,

          damit arbeite ich immer ich verwende VALUES( ?, ... ); blöd von mir das ich das in die Frage gestellt habe.

          vlg MB

  3. Was ich vergessen habe zu erwähnen das ich natürlich mit htmlspecialchars() und prepared statements arbeite. lg MB

    1. Hallo MB,

      Was ich vergessen habe zu erwähnen das ich natürlich mit htmlspecialchars()

      Du hast im Titel sowie in den Tags des Ursprungspostings die Stichwörter PHP und SQL verwendet. Geht es Dir um diese beiden Bereiche? Wenn ja, ist es zwar gut, dass Du htmlspecialchars() verwendest, wenn Du etwas in einem HTML-Kontext ausgeben möchtest; das hat aber mit der ursprünglichen Fragestellung nichts zu tun.

      Genau darum geht es bei einem Kontextwechsel: Wann möchte ich was in welcher Form an "etwas anderes" übergeben? PHP und SQL ist dabei HTML egal. Ebenso ist bspw. SQL egal, ob das jetzt von einem PHP-Skript kommt oder nicht. @dedlfix kann das bestimmt noch besser als ich erklären, falls der bereits verlinkte Kontextwechsel-Artikel nicht ganz klar sein sollte.

      und prepared statements arbeite.

      Auch das ist grundsätzlich gut. Aber welche Antwort hattest Du bei Deiner ursprünglichen Frage erwartet? Ich zumindest erkenne da erstmal keine prepared statements. Kann es sein, dass Du PDO evtl. nicht so einsetzt, wie man es könnte? Neben dedlfix haben ja auch schon Rolf und Tabellenkalk in diese Richtung vermutet.

      Hast Du noch etwas mehr Code oder kannst etwas ausführlicher beschreiben, worum es Dir eigentlich geht? Oder war Deine Ursprungsfrage rein akademisch?

      Gruß
      Dennis

      1. Hallo

        Auch das ist grundsätzlich gut. Aber welche Antwort hattest Du bei Deiner ursprünglichen Frage erwartet? Ich zumindest erkenne da erstmal keine prepared statements. Kann es sein, dass Du PDO evtl. nicht so einsetzt, wie man es könnte? Neben dedlfix haben ja auch schon Rolf und Tabellenkalk in diese Richtung vermutet.

        Sieht irgendwie so aus.

        Hast Du noch etwas mehr Code oder kannst etwas ausführlicher beschreiben, worum es Dir eigentlich geht? Oder war Deine Ursprungsfrage rein akademisch?

        Vermutlich ja. @MB verliert sich gerne einmal in der Mikrooptimierung. Die Frage, auf welche Art ein Query schneller zusammengebaut ist, gehört für mich offensichtlich dazu.

        Tschö, Auge

        --
        Wo wir Mängel selbst aufdecken, kann sich kein Gegner einnisten.
        Wolfgang Schneidewind *prust*
        1. Hallo Augo,

          Hast Du noch etwas mehr Code oder kannst etwas ausführlicher beschreiben, worum es Dir eigentlich geht? Oder war Deine Ursprungsfrage rein akademisch?

          Vermutlich ja. @MB verliert sich gerne einmal in der Mikrooptimierung. Die Frage, auf welche Art ein Query schneller zusammengebaut ist, gehört für mich offensichtlich dazu.

          xD ich glaube du hast den Nagel auf den Kopf getroffen. Ich verliere mich sehr leich in kleinigkeiten was meine projekte sehr erschwert.

          vlg MB

    2. Hallo

      Was ich vergessen habe zu erwähnen das ich natürlich mit htmlspecialchars() und prepared statements arbeite.

      Wie schon mehrfach angesprochen wurde, hat htmlspechialchars in SQL-Queries nichts zu suchen. Die Funktion dient dazu, Zeichenketten, die in ein HTML-Dokument eingebettet werden, zu entschärfen, indem in den Zeichenketten vorhandene, in HTML eine Sonderfunktion einnehmende Zeichen maskiert werden. Die selben Zeichenketten – und natürlich auch alle anderen – müssen für den Transport zu einer Datenbank hin für deren Kontekt maskiert werden. Für eine MySQL-Datenbank war das mit der alten Bibliothek von PHP die Funktion mysql_real_escape_string, für die Bibliothek mysqli wäre es entsprechend mysqli_real_escape_string. Das ist hier nur informativ aufgeführt, für dich gilt Anderes.

      Da du nach deinem eigenen Bekunden mit PDO arbeitest, musst du dir darüber keine Gedanken machen, weil PDO die Maskierung für dich regelt, wenn du die Fähigkeiten der Klasse benutzt. Die Seite zu execute zeigt in ihren Beispielen, dass der Query Als String mit Platzhaltern (:platzhalter) erstellt und die zu übergebenden Werte z.B. mit bindParam nachgereicht werden.

      Diese müssen nicht händisch maskiert werden, was die Sache enorm vereinfacht. Eine Sicherheitslücke wegen der an einer unauffälligen Stelle vergessenen Maskierung kann es so erst garnicht geben.

      Tschö, Auge

      --
      Wo wir Mängel selbst aufdecken, kann sich kein Gegner einnisten.
      Wolfgang Schneidewind *prust*
      1. Moin Auge

        , dass der Query Als String mit Platzhaltern (:platzhalter) erstellt und die zu übergebenden Werte z.B. mit bindParam nachgereicht werden.

        Ich arbeite mit ? nicht mit :colname. Wäre das n sicherheitstechnischer oder performance Grund???

        mein toller Dozent hat uns htmlspecialchars() eingebleut :/. Ich finde es auch etwas merkwürdig das ja mit bindeParam überflüssig wird.

        vlg MB

        1. Hi,

          mein toller Dozent hat uns htmlspecialchars() eingebleut :/. Ich finde es auch etwas merkwürdig das ja mit bindeParam überflüssig wird.

          Es hat beim Schreiben in die Datenbank schlicht und einfach absolut nichts verloren.

          Es wird benötigt, wenn Daten in HTML-Kontext gebracht wird. Ein SQL-Statement ist kein HTML-Kontext.

          cu,
          Andreas a/k/a MudGuard

        2. Hallo,

          Ich arbeite mit ? nicht mit :colname. Wäre das n sicherheitstechnischer oder performance Grund???

          weder, noch, würde ich sagen. Aber mit :colname musst du nicht mehr auf die Reihenfolge achten, die Zuordnung ergibt sich ja durch die Namen.

          mein toller Dozent hat uns htmlspecialchars() eingebleut :/.

          Im richtigen Kontext - nämlich Ausgabe von HTML-Code an den Browser - ist das ja auch korrekt. Im Kontext von SQL ist es dagegen Unsinn. Nicht nur unnötig, sondern sogar falsch.

          So long,
           Martin

          --
          Nothing travels faster than the speed of light with the possible exception of bad news, which obeys its own special laws.
          - Douglas Adams, The Hitchhiker's Guide To The Galaxy
        3. Hallo

          , dass der Query Als String mit Platzhaltern (:platzhalter) erstellt und die zu übergebenden Werte z.B. mit bindParam nachgereicht werden.

          Ich arbeite mit ? nicht mit :colname. Wäre das n sicherheitstechnischer oder performance Grund???

          Schaue dich in den Beispielen der Dokuseite zu prepare um. Es werden beide hier genannte und noch weitere Versionen der Übergabe der Werte gezeigt. Die Performanz wird sich nicht messbar unterscheiden und die Parameter werden in jedem Beispiel durch die Klasse fachgerecht behandelt.

          mein toller Dozent hat uns htmlspecialchars() eingebleut :/. Ich finde es auch etwas merkwürdig das ja mit bindeParam überflüssig wird.

          Nochmal, es geht nicht darum, dass htmlspecialchars nicht verwendet werden sollte. Es geht darum, dass es dort, wo es hingehört verwendet wird, nämlich, wenn HTML generiert wird. In SQL-Abfragen gehört es nicht hin, also hat es dort auch nichts zu suchen.

          Tschö, Auge

          --
          Wo wir Mängel selbst aufdecken, kann sich kein Gegner einnisten.
          Wolfgang Schneidewind *prust*
        4. Hi,

          , dass der Query Als String mit Platzhaltern (:platzhalter) erstellt und die zu übergebenden Werte z.B. mit bindParam nachgereicht werden.

          Ich arbeite mit ? nicht mit :colname. Wäre das n sicherheitstechnischer oder performance Grund???

          Vor allem ein Grund der Lesbarkeit.

          Bei zwei Parametern geht's ja noch, aber wenn Du viele Parameter hast, dann wird es schwierig, dann mußt Du immer wieder durchzählen, um zu erkennen, welcher Wert welchem Fragezeichen zugeordnet wird.

          cu,
          Andreas a/k/a MudGuard

          1. Hallo

            Auch wenn du nicht Adressat meiner Worte bist, lieferst du doch den besten Anlass, sie anzubringen. Deshalb …

            Ich arbeite mit ? nicht mit :colname. Wäre das n sicherheitstechnischer oder performance Grund???

            Vor allem ein Grund der Lesbarkeit.

            Bei zwei Parametern geht's ja noch, aber wenn Du viele Parameter hast, dann wird es schwierig, dann mußt Du immer wieder durchzählen, um zu erkennen, welcher Wert welchem Fragezeichen zugeordnet wird.

            Das ist ein ganz wichtiges Argument in Sachen Wartbarkeit des Codes. Wenn nach einem halben jahr Änderungen am Code anstehen, wird man in Queries mit mehreren „?“ mit Sicherheit mit abzählen anfangen müssen. Sprechende (sich selbst erklärende) Namen hingegen sollten nur in Ausnahmefällen Suchaktionen im Code auslösen. Die sind dann aber auch einfacher zu handeln.

            Das Gleiche gilt auch für die spätere Benutzung der abgefragten Werte. Wer die Werte nummeriert benutzt, hat sich schon bei der Codeerstellung ins eigene Fleisch geschnitten, falls später Änderungen in der Struktur der Benutzung dieser Werte anstehen. Das weiß sie/er nur noch nicht. Wird später eine weitere Spalte in die Abfrage eingefügt, die nicht an das Ende der Abfrage gehängt wird, ändert sich die Reihenfolge der Spalten des Ergebnisses und das Zählen beginnt. Ein Name bleibt hingegen ein (hoffentlich wiedererkennbarer) Name.

            Tschö, Auge

            --
            Wo wir Mängel selbst aufdecken, kann sich kein Gegner einnisten.
            Wolfgang Schneidewind *prust*
            1. moin Auge,

              sehr einleuchtend. Danke dafür.

              MB

        5. Hallo MB,

          , dass der Query Als String mit Platzhaltern (:platzhalter) erstellt und die zu übergebenden Werte z.B. mit bindParam nachgereicht werden.

          Ich arbeite mit ? nicht mit :colname. Wäre das n sicherheitstechnischer oder performance Grund???

          nein, das sollte keinen Unterschied machen. Die benannte Schreibweise mit dem Doppelpunkt ist nur besser lesbar und weniger Fehleranfällig, weil dann die Reihenfolge der Zuordnung keine Rolle spielt.

          mein toller Dozent hat uns htmlspecialchars() eingebleut :/.

          Dann hat er entweder keine Ahnung und/oder es nicht richtig erklärt oder bei Dir ist was falsches hängen geblieben. Oder von beidem etwas.

          Ich finde es auch etwas merkwürdig das ja mit bindeParam überflüssig wird.

          Ne, überflüssig ist das nicht. Die bind()-Funktionen ersetzen nicht htmlspecialchars() o.ä.. Es kommt immer darauf an, von wo nach wo Du Daten "verschieben" möchtest.

          Eigentlich ist das mit dem Kontextwechsel vom Prinzip her gar nicht so fürchterlich kompliziert. Stell Dir vor, Du möchtest einen Text vom Englischen ins Deutsche übersetzen. Beide Sprachen haben bestimmte Regeln, auch Grammatik oder Syntax genannt. Diese Regeln musst Du kennen und anwenden. Was machst Du also? Du schaust Dir die Regeln im Duden an und übersetzt den Text manuell. Da Du etwas ins Deutsche übersetzen möchtest, siehst Du hier auch, dass Dich ein französisches Wörterbuch nicht weiterbringt. Das würdest Du nur brauchen, wenn Du den Text ins Französische übersetzen wolltest.

          Wenn Du jetzt Englisch = PHP, Deutsch = SQL und Französisch = HTML setzt, bist Du beim Verständnis des Kontextwechsels schon nah dran. Die Wörterbücher in dem Beispiel entsprechen den jeweiligen Specs der Systeme.

          Jetzt hast Du keine Lust mehr, immer wieder ins Wörterbuch zu gucken und Deine Texte von Hand zu übersetzen. Du nimmst Dir also ein Übersetzungsprogramm. Das kennt schon viele der Regeln, Du gibst ihm Deinen Englischen Text und bekommst ihn auf Deutsch zurück. Wichtig ist hier nur, dass Du im Programm die richtige Sprache einstellst, hier also "von Englisch nach Deutsch" und nicht bspw. "von Englisch nach Französisch". Das ist im Endeffekt das, was die ganzen escape()-Funktionen machen. Möchtest Du etwas in die SQL-Datenbank schreiben, nimmst Du die SQL-escape-Funktion. Möchtest Du hingegen etwas als HTML auf Deiner Seite ausgeben, nimmst Du die HTML-escape-Funktion.

          Kommen wir zum Schluss: Nach einiger Zeit nervt es Dich, dass Du die Texte immer in das Übersetzungsprogramm eingeben musst, weil Du da immer noch einiges beachten musst. Was machst Du also? Du stellst einen Dolmetscher ein. Dem sagst Du einfach in Deiner Sprache, was Du möchtest und er soll sich um den Rest kümmern. Das wäre dann sozusagen das Grundprinzip von PDO und Co. Das übernimmt die Übersetzung von PHP (Englisch) nach SQL (Deutsch) und zurück.

          Hier müssen wir noch eine Besonderheit beachten, um die Analogie zu vervollständigen: Stell Dir vor, Du hast ein Dokument, sagen wir eine Rechnung. Oben ist z.B. Dein Firmenlogo drauf, das sieht auf jeder Rechnung gleich aus. Wir haben also eine Vorlage (Template). Du möchtest aber nicht, dass der Dolmetscher Dir Dein Logo ersetzt, sondern nur die Rechnungspositionen. Das machst Du, indem Du in der Vorlage Platzhalter einbaust. Nur hier soll der Dolmetscher übersetzen. Das gleiche passiert bei PDO: Das SQL-Statement ist Deine Vorlage und hat Platzhalter. Und mit den bind()-Funktionen sagst Du dem Dolmetscher jetzt in Deiner Sprache (PHP bzw. Englisch), was Du machen möchtest. Den Rest erledigt er dann für Dich.

          Sorry für den langen Text. Ich hoffe, er kann etwas zum Verständnis beitragen. Falls nicht, frag einfach nach.

          Gruß
          Dennis

          1. nein, das sollte keinen Unterschied machen. Die benannte Schreibweise mit dem Doppelpunkt ist nur besser lesbar und weniger Fehleranfällig, weil dann die Reihenfolge der Zuordnung keine Rolle spielt.

            Siehe meine andere Antwort...

            mein toller Dozent hat uns htmlspecialchars() eingebleut :/.

            Oh, er prügelt euch blaue Flecken in Pastellfarbe (bleu) ein? Sonst wär's doch eingebläut... :-D

            Dann hat er entweder keine Ahnung und/oder es nicht richtig erklärt oder bei Dir ist was falsches hängen geblieben. Oder von beidem etwas.

            Oder er ist auch ein Mikrooptimierer. Hypothetisch könnte man ja sagen: "Ich mache die HTML Maskierung beim Schreiben in die Datenbank. Das passiert SELTEN. Beim Abrufen der Daten, was im Vergleich zum Schreiben HÄUFIG vorkommen sollte, bekomme ich fertig maskierte Daten geliefert und spare damit netto ein paar CPU Zyklen ein." Rein praktisch ist das natürlich falsch verstandener Umgang mit Kontexten und Sparen am falschen Ende :)

            Rolf

            1. Moin RolfB

              Dann hat er entweder keine Ahnung und/oder es nicht richtig erklärt oder bei Dir ist was falsches hängen geblieben. Oder von beidem etwas.

              Oder er ist auch ein Mikrooptimierer.

              keines Fals. Er ist so ein Hardcoder, unterrichtet KEIN OOP obwohl OOP am Bach is und mischt deutsch und englisch in die bezeichnungen wie z.B. setze_Color().

              Aber ich will aufhören über Unbekannte dritte berechtigter weise zu lästern. Es gehört sich nicht. Ich entschuldige mich.

              lg MB

              1. Hallo,

                keines Fals. ... am Bach is und mischt deutsch und englisch in die bezeichnungen wie z.B.

                Unbekannte dritte berechtigter weise

                Naja, was du hier so mischt, darüber schweigen wir besser auch...

                Gruß
                Kalk

            2. Hallo Rolf,

              nein, das sollte keinen Unterschied machen. Die benannte Schreibweise mit dem Doppelpunkt ist nur besser lesbar und weniger Fehleranfällig, weil dann die Reihenfolge der Zuordnung keine Rolle spielt.

              Siehe meine andere Antwort...

              ich denke mal Du meinst diese Antwort. Rein theoretisch kann das schon sein, dass die "Fragezeichen-Methode" schneller sein könnte. Praktisch sollte das keinen oder einen nicht messbaren Unterschied machen. Man darf ja auch nicht vergessen, was da im Hintergrund noch so alles abläuft. Die heutigen Compiler und (Zwischen-)Caches machen auch immer wildere Sachen. Wenn man möchte, kann man das gerne untersuchen. Sinnvoll wird das i.A. nicht sein, wenn man nicht gerade nen Compiler o.ä. baut.

              Mit der Argumentation („Das Fragezeichen als Platzhalter ist [...] einfacher zu parsen als :meinTollesFeld“) kann man übrigens auch dafür plädieren, dass man möglichst kurze Variablennamen verwenden sollte. $a ist theoretisch bestimmt auch schneller geparst als $meinTollesFeld. Und dann landet man schnell dabei, dass man auch einfach nur Einsen und Nullen schreiben könnte...

              Ich hatte aber auch erst überlegt das anzumerken. Und mich dann dagegen entschieden: Erstens aus zuvor genannten Gründen. Zweitens sagte MB selbst, dass er sich häufig in solchen Dingen verheddert. Und es klang nicht so, dass er das immer toll findet. Und da ich denke, dass der Hinweis keinen wirklichen Mehrwert bietet und MB evtl. sogar das Leben erschwert, weil er sich zu sehr damit beschäftigt, hab ich es dann weggelassen. Man muss sich oder anderen das Leben ja nicht noch schwerer machen.

              Dann hat er entweder keine Ahnung und/oder es nicht richtig erklärt oder bei Dir ist was falsches hängen geblieben. Oder von beidem etwas.

              Oder er ist auch ein Mikrooptimierer. Hypothetisch könnte man ja sagen: "Ich mache die HTML Maskierung beim Schreiben in die Datenbank. Das passiert SELTEN. Beim Abrufen der Daten, was im Vergleich zum Schreiben HÄUFIG vorkommen sollte, bekomme ich fertig maskierte Daten geliefert und spare damit netto ein paar CPU Zyklen ein." Rein praktisch ist das natürlich falsch verstandener Umgang mit Kontexten und Sparen am falschen Ende :)

              Mikrooptimierung ist ja nicht per se schlecht. Es gibt schließlich Anwendungen, wo man alles herausholen muss. Das weiß man dann aber vorher. Oder man findet tatsächlich einen problematischen Flaschenhals. Dann muss man auch kleine Optimierungen in Betracht ziehen. Aber erst dann und nicht vorher. Vorher zählt das von Dir Gesagte: Einfache Lesbarkeit und Wartungsfreundlichkeit.

              Wenn man in Deinem Beispiel mal die Datenbank ausklammert (das wäre in den meisten Fällen wohl Unsinn) gibt es aber den beschriebenen Anwendungsfall bzw. die Vorgehensweise sogar recht häufig: Nennt sich Caching ;-) Und das ist kein falsch verstandener Umgang, halt nur ein anderes Themengebiet :-)

              Gruß
              Dennis

              1. Mit der Argumentation („Das Fragezeichen als Platzhalter ist [...] einfacher zu parsen als :meinTollesFeld“) kann man übrigens auch dafür plädieren, dass man möglichst kurze Variablennamen verwenden sollte.

                Nein, habe ich anders gemeint. Es geht mir nicht um die Laufzeit. Wer die Laufzeit optimieren will, ersetze PHP durch eine Compilersprache...

                Es ist das Pferdearsch-Problem. Es ist einfach programmiertechnisch aufwändiger, statt ? nach :dings<wortende> zu suchen und dann noch die gefundenen Namen auf ein Array mit benannten Parametern zu mappen. Und darum - vermute ich - hat der Erfinder der Prepared Statements es erstmal mit Fragezeichen gelöst und einem 1:1 Mapping von Fragezeichenposition zur Werteposition. Das ist viel einfacher zu programmieren, und ja, es ist auch deutlich fixer. 1980 - oder wann auch immer die prepared statements erfunden wurden - war das relevant.

                Bis dann irgendwer mal auf die Idee kam, dass Namen sinnvoller sein könnten, hatten schon viele andere das Fragezeichen als Syntax übernommen. Und dann kam der Fluch der Kompatibilität: Mit benannten Parametern muss man das execute()-API zur Datenbank ändern, weil das Parameter-Array auf einmal nicht mehr ein Werte-Array ist (ggf. ergänzt durch einen String mit Typ-Hinweisen), sondern plötzlich aus richtigen Parameterdeskriptoren bestehen muss. Zumindest den MySQLern war das zu aufwändig, da gehen bis heute nur die Fragezeichen.

                Rolf

                1. Hallo Rolf,

                  Mit der Argumentation („Das Fragezeichen als Platzhalter ist [...] einfacher zu parsen als :meinTollesFeld“) kann man übrigens auch dafür plädieren, dass man möglichst kurze Variablennamen verwenden sollte.

                  Nein, habe ich anders gemeint. Es geht mir nicht um die Laufzeit. Wer die Laufzeit optimieren will, ersetze PHP durch eine Compilersprache...

                  ok, dann ist das (zumindest bei mir) falsch rübergekommen. Sorry.

                  Es ist das Pferdearsch-Problem. [...]

                  Stark! Das kannte ich in der Form noch nicht :-) Merke ich mir. Vor dem Hintergrund liest sich Dein Beitrag auch direkt ganz anders und ich kann Dir in dem Punkt natürlich zustimmen.

                  Eine Einschränkung habe ich aber: Es ist klar, dass „die Sachen irgendwo herkommen“ und vieles auch „irgendwie die Zeit überdauert“. Es ist auch nicht schlecht zu wissen, wo aus heutiger Sicht so einige „Merkwürdigkeiten“ herkommen. Manchmal könnte oder sollte man das aber vielleicht auch einfach mal ignorieren, sonst nimmt die Pferdearsch-Geschichte ja nie ein Ende :-)

                  Gruß
                  Dennis

          2. schöne Analogie lg MB

            1. Hallo MB,

              schöne Analogie lg MB

              „in Schönheit gestorben“ (wie ein Fußballer nach einem tollen Spielzug, der aber doch in keinem Tor resultiert, sagt) hilft leider nicht weiter. Meine Frage an Dich wäre: Ist sie (für Dich bzw. Dein Verständnis) ein wenig hilfreich? Dann könnte man sie ggf. anpassen und später mal wieder verwenden, wenn es um Kontextwechsel geht. Ist sie nicht hilfreich, ist sie Müll. Dann müsste man sich das nächste mal vielleicht was anderes überlegen.

              Gruß Dennis

              1. Ist sie (für Dich bzw. Dein Verständnis) ein wenig hilfreich?

                Ja ich weis was du meinst. Ich hab mit kontextwechsel gearbeitet, escapen usw. Ist Unschön. daher weis ich worauf du anspielst. Also wäre ich dir da leider keine hilfe. Aber die analogie ist für meine begriffe gut nur n bissl brüchig finde ich und ausdehnend. Bin aber auch sprachlich net fit muss ich dazu sagen.

                vlg MB

        6. Das Fragezeichen als Platzhalter ist ziemlich verbreitet und für den Datenbanktreiber einfacher zu parsen als :meinTollesFeld. Wenn ich die MySQL Doku richtig lese, unterstützt MySQL nur das Fragezeichen und keine benannten Parameter. Deshalb ist im mysqli Interface auch nur das Fragezeichen unterstützt.

          Die Benennung von Parametern ist ein Feature, dass manche Datenbanken nativ mitbringen (z.B. MS SQL Server). PDO ist ein Datenbanktreiber, der diese Unterschiede neutralisiert und darum kannst Du in PDO sowohl Namen als auch Fragezeichen als Parameter-Marker nutzen (nur nicht gemischt in einem Statement). PDO baut das beim prepare() passend für die verwendete Datenbank um. Wenn Du direkt die Fragezeichen verwendest, hast Du einen minimalen Laufzeitvorteil, erkaufst den aber mit einem Nachteil im Wartungsaufwand, weil Du bei jeder Änderung genau abzählen musst welches Fragezeichen wo steht. (Quelle). Sinn von prepared statements ist es jedenfalls, die DATEN nicht mehr dynamisch ins SQL einzubauen, und sich damit die SQL-Escaperei zu sparen. Alles andere muss in den SQL String, weil Schlüsselworte und dynamische Elemente sich nicht preparen lassen.

          Rolf