MB: Validierung: preg_match() oder filter_var() oder eigene Klasse?

moin Community,

bezogen auf die Valigierung (z.B. HTML-Formularen) kenne ich drei Formen.

  • preg_match()
  • filter_var()
  • oder eigene Validierung Klasse mit RegEx Verwendung

bezogen auf die ersten beiden Punkte lohnt sich noch eine Klasse die im letzten Punkt aufgeführt habe? Ich mein, wenn da ein Spezialfall auftritt, für den es keine Filter Funktion gibt, wird sich wohl eine zusammengesetzter Filter aus den oberen genannten Filter Funktionen basteln lassen oder nicht?

vlg MB

  1. Tach!

    bezogen auf die Valigierung (z.B. HTML-Formularen) kenne ich drei Formen.

    • preg_match()
    • filter_var()
    • oder eigene Validierung Klasse mit RegEx Verwendung

    Ich kenne da noch eine ganze Menge mehr Formen. Eigentlich gibt es da keine begrenzende Zahl. Es gibt einige Standardvalidierungen, aber letztlich entscheidet der Anwendungsfall, was valide ist und was nicht, und damit wieviele Validisierungsverfahren man einsetzen muss.

    bezogen auf die ersten beiden Punkte lohnt sich noch eine Klasse die im letzten Punkt aufgeführt habe? Ich mein, wenn da ein Spezialfall auftritt, für den es keine Filter Funktion gibt, wird sich wohl eine zusammengesetzter Filter aus den oberen genannten Filter Funktionen basteln lassen oder nicht?

    Nicht unbedingt. Damit kann man vielleicht ein paar Standardfälle abdecken, aber nicht die Individualitäten. Wenn du dem Verwender die Freiheit geben möchtest, eigene Validatoren einzusetzen, solltest du eine Schnittstelle definieren, über die das erfolgen soll, schon damit da eine Einheitlichkeit ins System kommt. Das kann eine (abstrakte) Klasse sein, von der geerbt werden muss, oder ein Interface, das man implementieren muss. Und man sollte da auch vorsehen, dass eine Validierung auch mehr als ein Feld umfassen kann. Ein Passwortfeld auf Gleichheit mit dem Passwortwiederholungsfeld zu prüfen, oder dass Passwort und Nutzername nicht übereinstimmen, braucht keine der oben genannten Möglichkeiten, dafür aber die Möglichkeit, auf mindestens zweier Felder zuzugreifen.

    dedlfix.

    1. Moin dedlfix,

      klingt sehr einleuchtend! Hast du mir ein kuzes Anwendungsbeispiel geben? Ich kann mir darunter nix vorstellen? z.B. Valigator::hash() oder class HomeModel implements IValidator {} oder class HomeModel extends Validator { function valide() } sowas? Sorry ich hab keine Ahnung. zumal muss ich ja auch noch die Superklassen irgendwie einbetten.

      Es würde sich für meine Begriffe nur ein Interface der Superklasse anbieten damit die Supklassen die abstrakten Methoden der Superklasse erben. Hardcodiertes Beispiel von Klassen reicht wenns geht.

      vlg MB

      1. Tach!

        klingt sehr einleuchtend! Hast du mir ein kuzes Anwendungsbeispiel geben?

        Was muss denn wer wissen? Der Controller, oder welcher Teil auch immer die Validierung anstößt, muss wissen ob das Model valide ist. Das ist ein Funktionsaufruf mit booleschem Ergebnis. Und die View will am Ende wissen, welche Meldungen generell und welche zu bestimmten Feldern ausgegeben werden sollen. Also muss der Validierungsprozess auch noch eine solche Struktur liefern. Eigentlich ist dies das Hauptergebnis und die boolesche Information nur für Entscheidungen wichtig. Ihren Wert kann man auch aus der Anzahl der Fehlermeldungen ermitteln (0 == valide). Das wäre also das eine Interface.

        Der Validator hingegen muss auf das Model zugreifen können, um die Werte zu prüfen. Er braucht auch ein Regelwerk, das er abarbeiten muss. Das wird wohl am besten ein Array mit den Regeln sein.

        Die Regeln selbst arbeiten unterschiedlich. Eine Required-Regel braucht nur einen Wert, den sie auf null oder Leerstring testen muss. Eine Stringlängen-Regel braucht den Wert sowie eine Min- und Max-Angabe. Eine Passwort-Gleichheit-Regel braucht stattdessen zwei Werte. Die einzige Gemeinsamkeit ist die Aussage, ob die Regel eingehalten wurde oder nicht. Das könnte man so lösen, dass die benötigten Angaben als Parameter in den Konstruktor gegeben werden. Je nach Regel sieht der unterschiedlich aus. Das Interface, das die Regel-Klassen implementieren, besteht nur aus einem Funktionsaufruf, der die eigentliche Prüfung an den Werten ausführt, die der Konstruktor entgegengenommen hat, und true/false liefert. Eine andere Möglichkeit wäre, dass die Prüfung den Meldungstext produziert, oder null/false, wenn es nichts zu meckern gibt, oder wie auch immer man das implementieren möchte.

        zumal muss ich ja auch noch die Superklassen irgendwie einbetten.

        Da stellt sich die Frage, ob man dafür überhaupt Superklassen braucht. Gibt es denn Code, den man mehrfach implementieren würde und den auszulagern sinnvoll ist?

        Bei den Regeln eher nicht. Beim Validator wird das jedoch der Fall sein. Wenn deine Models typischerweise POPOs sind (Plain Old PHP Object), dann sind die Validatoren zwar je nach Model mit unterschiedlichen Regelwerken auszustatten, aber die Abarbeitung wird immer nach demselben Prinzip ablaufen. Letzteres wäre eine Aufgabe für die Superklasse.

        Andererseits kann es sich ergeben, dass das Model kein POPO ist, sondern irgendeine andere Datenstruktur, dass braucht man eine andere Ausführung als die für den POPO-Validator. Also wird dieser Validator nicht von der Superklasse erben, das Interface in Richtung Controller bleibt aber dasselbe.


        PHP ist je eine Sprache, die normalerweise im Quelltext ausgeführt wird. Unter anderem deshalb ist es üblich, dass die Frameworks alle Open Source sind. Man kann da also durchaus auch mal durch diese schauen, wie deren Vorgehensweise ist. Am besten fängt man da in der Dokumentation an, um zu sehen, wie deren Implementation anzuwenden ist. Und wenn das gefällt, kann man ja den Code dazu anschauen.

        Das was ich beschrieben habe, ist nur eine Möglichkeit, nicht aber die einzige oder gar die einzig wahre. Mir persönlich gefallen beispielsweise solche Vorgehensweisen nicht, bei denen man jede Menge Strings angeben muss, um zu beschreiben, was man erreichen möchte. Dabei muss man immer wissen oder in der Doku nachschauen, wie der String konkret zu schreiben ist, und IDEs mit Autovervollständigung können dabei so gut wie nicht unterstützend mithelfen. Wenn schon Strings, dann sollten die hinter Klassenkonstanten versteckt sein. Dann kann man den Namen der Klasse eingeben und bekommt alle Möglichkeiten aufgezählt.

        Um mal zwei Beispiele zu nennen von Frameworks die mir spontan eingefallen sind, deren Vorgehensweise mir nicht gefällt: Zend Framework - Forms and actions: die Anwendung der InputFilter als verschachteltes Array in bis zu vier Ebenen. Laravel Validation: mit | verkettete Stringwürste.

        dedlfix.

  2. OOP in der Praxis:

    Die Klasse hast Du doch schon, nämlich die Klasse welche das Modell beschreibt. Und eine Instanz dieser Klasse hat Methoden, z.B. eine Methode womit HTTP Request Parameter geparst werden. Qualifiziere Letztere so, dass sie in der Lage ist, Benutzereingaben, die ja Request Parameter sind, passend zum Modell zu validieren. MfG

    1. Tach!

      Die Klasse hast Du doch schon, nämlich die Klasse welche das Modell beschreibt. Und eine Instanz dieser Klasse hat Methoden, z.B. eine Methode womit HTTP Request Parameter geparst werden. Qualifiziere Letztere so, dass sie in der Lage ist, Benutzereingaben, die ja Request Parameter sind, passend zum Modell zu validieren.

      Kann man machen. Funktioniert auch. Doch dann hat man eine Klasse, die sich am Ende um viele Dinge zu kümmern hat. Diesen Weg geht man heutzutage nicht mehr so gern. Stattdessen separiert man lieber die Aufgaben und erstellt spezialisierte Klassen, die sich um eine einzige Aufgabe kümmern. Dass das Model wissen muss, welche Daten valide sind, kann man ja noch als dessen Aufgabe ansehen. Würde aber bedeuten, dass die Prüfroutinen eingebaut, für jede Modelklasse kopiert oder geerbt sind. Die Herausforderungen sieht man dann, wenn man eigene Validierungen für mehrere Models hinzufügen möchte und dann anfängt, von der Superklasse eine Zwischenklasse zu erben, in die man diese gemeinsame Validierung einbaut, und die man dann beerben kann. Sieht am Anfang vielleicht noch ganz schnuckelig aus, aber kann auch in Wildwuchs enden.

      Warum aber soll das Model Ahnung von HTTP-Requests haben? Und wieviel Ahnung von der Welt soll es noch haben, wenn andere Datenquellen verwendet werden sollen?

      Die Komplexität einer Anwendung aufgrund der zu erfüllenden Aufgaben hat man am Ende immer. Die Frage, ob man diese Komplexität gebündelt an wenigen Orten ansiedelt oder in kleine in sich einfacher überschaubare Einheiten aufspaltet, beantwortet man heutzutage eher auf letztere Weise.

      dedlfix.

    2. Hi pl,

      sehe ich exakt genauso wie dedlfix. Wenn man klein anfängt ist es bescheuerd eine Validierungsklasse zu abstrahieren und zu verwenden. Wenn man komplexe Framework strukturen hat egal welche sehe ich es gegeben und für meine Begriffe obligat eine Validierung zu kapseln und für jedes Model zu referenzieren. Aber da ich bin blutiger Anfänger bin frage profies bzw. euch 😉.

      vlg MB

      1. Guckst Du dir eigentlich auch mal andere Frameworks an wie dedlfix das mal empfohlen hat? Also, ich habe das ja auch gemacht, auf dem langen Weg zu meinem Framework. Begonnen zum Beginn des vorletzten Jahrzehnts, stand zuerst die Aufgabe, Anwendungen und Dokumentationen, z.T. interaktiv auf einer Domäne zu vereinen -- da war die Idee geboren.

        Aber ach, im produktiven Umfeld war überhaupt gar keine Zeit, ein Framework zu entwickeln! So habe ich unendlich viel meiner privaten Freizeit geopfert. Entscheidend ist tatsächlich, von Anderen zu lernen und das Meiste was ich dabei gelernt habe ist, wie man es nicht machen sollte.

        Heute ist mein FW ein reines Vergnügen. Und zwar deswegen, weil neue Anwendungen damit im Handumdrehen entwickelt sind und sich nahtlos ins Gesamtkonzept fügen. Hier brauchte ich neulich einen Platzhalter für die Accept-Language. Die Sache war in <5 Minuten erledigt, ein Interface hinzuconfigurieren dauert 10 Sekunden und die 7 Zeilen fürs Interface zu schreiben vielleicht 2..3 Minuten und schließlich noch 2 Klicks zum Hochladen.

        Der Name des interface steht als Kommentar im Quelltext. Wartungsfreundlicher gehts nicht.

        MfG

        1. hi pl,

          ja habe ich. Für meinen teil habe ich CakePHP, banshee überflogen. ZendFramework möchte ich noch machen. Die Frameworks die ich überflogen habe sind schlecht "im Code" dokumentiert. Ich schätze PHPDoc sehr. Ich dokumentiere meinen Code ja auch selbst damit für mich (Ich vergesse so oft Wichtige Dinge im Code). Vermutlich ist eine Quellcode Dokumentation nicht sehr perfomant und nicht von bedeutung für den Anwender und da hat man es denke ich für die Anwendung wegelassen was ich ja auch gut finde. Nur zum lernen ist es kacke. Tschuldige die wortwahl.

          vlg MB

          1. Wenns Kacke ist dann ist es so. Und wenn jemand Monate braucht, um ein FW zu verstehen ist das Kacke, was denn sonst. Hab ich alles schon erlebt und beim genauen Hingucken dann festgestellt, dass der Oberguru von OOP überhaupt keine Ahnung hatte und von Zweckmäßiger Programmierung sowie Teamarbeit schon gar nicht. Neue Kollegen als Idioten hinstellen, das können solch Leute dann aber erstaunlicherweise umso besser.

            Ich war mal bei einem, der hat vehement an seinem EmbedPerl festgehalten, obwohl ich bereits nach wenigen Stunden festgestellt habe, dass das bezogen auf sein programmiertechnisches Vorhaben völliger Unsinn ist. Dementsprechend chaotisch sah der Code aus den er als Programmierer und Geschäfzsführer in einer Person auch noch ganz toll fand obwohl es sich bei einer Umstellung auf eine andere Datenbank abzeichnete dass dieser Vorgang mindestens ein halbes Jahr dauern würde weil tausende Scripte geändert werden mussten.

            Der Begriff Data-Access-Layer war diesem Schloch absolut fremd und das Einzige ws der von OOP verstanden hat war wie man mit Moose, einem Wrapper für Perls OOP, Objekte erzeugt, das ist noch unter dem Niveau eines Praktikanten der gerade anfängt OOP zu verstehen. Den seine Klassen hatten, infolge endloser Erweiterungen bzw. Ableitungen, Namen die selbst auf hochauflösenden Monitoren einen Zeilenumbruch erforderten. Und anstatt einer Main-Instanz schwirrten in seinen Scriptn unzählige andere Instanzen rum die ohne Not zwischen den verschiedensten Klassen hin und hergereicht wurden und was dabei passierte wurde über ungezählte Globale Variablen geregelt die irgendwo auftauchten um dann wieder ins Nirwana zu verschwinden.

            Bei so einem Schloch zu arbeiten taugt bestenfalls als Alibi. MfG

            1. Wenns Kacke ist dann ist es so.

              Bei so einem Schloch zu arbeiten taugt bestenfalls als Alibi.

              Vielen Dank für Deine Motivationshilfe, diesen Tag und seinen Herausforderungen in angemessener Reflektion zu begegnen.

          2. Tach!

            Vermutlich ist eine Quellcode Dokumentation nicht sehr perfomant und nicht von bedeutung für den Anwender und da hat man es denke ich für die Anwendung wegelassen was ich ja auch gut finde.

            Kommentare sind natürlich eine Vergrößerung des Codes. Sie müssen mit eingelesen werden und übersprungen werden muss. Aber dass sie merklich ins Gewicht fallen, ist vermutlich nicht der Fall. Wenn doch, ist wohl eher der Rechner generell zu schwach, auf dem das ausgeführt werden soll. Das Dateisystem verwendet einen Cache, häufige Zugriffe werden also nicht immer von der langsamen Festplatte gelesen, wenn es nicht sowieso schon eine SSD ist. Aktuelle PHP-Versionen haben zudem einen eingebauten OP-Code-Cache, so dass die Dateien auch nicht immer wieder neu geparst werden müssen. Performance ist eher weniger der Grund für eine weggelassene Dokumentation. Zudem ist der Anwender (Seitenbesucher) letztlich nicht der eigentliche "Kunde" des Frameworks sondern der Verwender, der Programmierer, der seinen Code auf dem des Frameworks aufsetzt.

            Ich denke eher, dass man sich generell nicht besonders gut in die Gedankenwelt anderer hineinversetzen kann, schon gar nicht in die von unbekannten Leuten, die in Zukunft den Code verwenden, den man da geschrieben hat. Deshalb ist es oftmals problematisch, eine Dokumentation zu verfassen, die alle Fragen klärt.

            dedlfix.

        2. Hallo pl,

          Hier brauchte ich neulich einen Platzhalter für die Accept-Language.

          Was du dort schreibst, ist mMn. nicht richtig.

          Ein Browser sendet beispielsweise diesen Header im Request:

          Accept-Language: de,en-US;q=0.7,en;q=0.3

          Zum Aushandeln der Sprache sind nur die ersten beiden Buchstaben vor dem Komma von Interesse,

          Ihr Browser möchte als Sprache: de

          Was ist, wenn es das Dokument in englisch, italienisch und spanisch gibt, aber nicht in deutsch gibt? Welche Version soll ausgeliefert werden? Richtig – englisch. Diese Information hast du großzügig mithilfe deines einfachen regulären Ausdrucks wegkonfiguriert.

          Warum baust du überhaupt etwas nach, was die Browser schon von sich aus können?

          Ich empfehle das Studium von https://www.w3.org/International/questions/qa-when-lang-neg

          Bis demnächst
          Matthias

          --
          Rosen sind rot.