Eddie: Methoden-Parameter: immer alles validieren?

Hallo allerseits,

mal eine bloede Frage: bei Java werden ja beim Aufruf einer Methode die Parametertypen automatisch validiert:

Sowas hier...:

  
public function x(int value){}  
x('a');  

... ergibt also automatisch einen Fehler. Wie ist das bei PHP5 genau? Muss ich da wirklich IMMER alles prüfen? Ist also sowas unbedingt nötig:

  
public function x(int $value)  
{  
  if (!is_int($value)) { throw new Exception();}  
}  
x('a');  

Danke für eure Hilfe,
Eddie

--
Old men and far travelers may lie with authority.
  1. Hallo,

    Wie ist das bei PHP5 genau?

    PHP hat nicht solche strengen Datentypen. Funktionen akzeptieren generell alles und  innerhalb wird es dann möglichst weiterverwendet.

    Muss ich da wirklich IMMER alles prüfen? Ist also sowas unbedingt nötig:

    public function x(int $value)
    {
      if (!is_int($value)) { throw new Exception();}
    }
    x('a');

      
    Nein, das ist nicht nötig. Ob es sinnvoll ist, hängt davon ab, was du machst. (Soweit ist das weiß ist aber sowohl das public als auch das int in der ersten Zeile in PHP nicht erlaubt.)  
      
    Beipsiel:  
      
    function quadrat($num)  
    {  
      return $num\*$num;  
    }  
      
    Hier sollte quadrat('123') genau das gleiche zurückliefern wie quadrat(123) oder wie quadrat(123.0) und vermutlich auch wie quadrat(/123.0/) (ungetestet...). PHP wandelt also Typen automatisch um falls erforderlich. Klappt das nict (bei quadrat('hans') z.B.) gibt es einen Laufzeitfehler.  
      
      
    Jonathan
    
    -- 
    [Selfcode:](http://emmanuel.dammerer.at/selfcode.html) [ie:( fl:{ br:> va:) ls:& fo:) rl:? ss:} de:> js:| ch:? mo:} zu:)](http://www.peter.in-berlin.de/projekte/selfcode/?code=ie%3A%28+fl%3A%7B+br%3A%3E+va%3A%29+ls%3A%26+fo%3A%29+rl%3A%3F+ss%3A%7D+de%3A%3E+js%3A%7C+ch%3A%3F+mo%3A%7D+zu%3A%29)
    
    1. Hi there,

      Klappt das nict (bei quadrat('hans') z.B.) gibt es einen Laufzeitfehler.

      Ich würd' sagen, wenn Du 'hans' in PHP quadrierst kommt 0 raus und kein Laufzeitfehler...

  2. Wie ist das bei PHP5 genau? Muss ich da wirklich IMMER alles prüfen?

    PHP kennt wie Perl nur Skalare, ist also wesentlich lockerer im Datentyp handling als Java oder MS-Sprachen. Was ja auch Sinn macht, denn wir haben ja nur eine zusätzliche Einstellung auf Parameter- bzw. Variablenebene, von der ich nie genau verstanden habe, was die soll.

    Du machst also brav Deine IS_NUMERIC-Prüfungen, wenn Du numerische Daten erwartest und wenn geteilt werden soll, dann weisst Du schon was.   ;)

    Zum Prüfen: Man prüft ja nicht aus Spass, Du musst immer auf etwas prüfen, dafür braucht man diese Datenypen nicht. Datentypen haben natürlich auch gewisse Vorteile, vgl.
    http://de.wikipedia.org/wiki/Datentyp

  3. Moin!

    Wie ist das bei PHP5 genau? Muss ich da wirklich IMMER alles prüfen? Ist also sowas unbedingt nötig:

    public function x(int $value)
    {
      if (!is_int($value)) { throw new Exception();}
    }
    x('a');

      
    Kurze Frage, lange Antwort.  
      
    Nein, du mußt nicht alles immer prüfen. Jedenfalls nicht diese sinnlosen Details wie "ist die Variable wirklich ein Integer", sofern dieses Detail keine Rolle spielt.  
      
    Was du aber tun solltest, ist dich mit testgetriebener Entwicklung zu beschäftigen. Denn das würde dir diverse Dinge erleichtern und teilweise erst erlauben, darunter:  
     - hohe Softwarequalität, geringe nachträglich zu behebende Fehlerzahl  
     - Freiheit, alle Funktionen/Methoden beliebig neuzuschreiben, ohne das bestehende Gesamtsystem kaputtzumachen  
     - die Sicherheit, dass eine Funktion/Methode im Live-Einsatz genau das macht, was du im Test spezifiziert hast.  
      
    Gerade der letzte Punkt ist für deine Fragestellung hier entscheidend. Wenn du testgetriebene Entwicklung anfängst, dann schreibst du zuallererst mal einen Test, der deine Funktion/Methode, die du zu schreiben gedenkst, auf die allereinfachste Art aufruft. Was natürlich scheitert, weil deine Funktion noch gar nicht existiert. Dadurch vergißt du nicht, alle notwendigen Dateien auch wirklich einzubinden und die Namen korrekt zu benennen. Am Ende dieser ersten Runde hast du einen Test, der grob nur die Existenz der Funktion testet, und eine korrekte, aber leere Funktion.  
      
    Dann kommt der nächste Test: Du gibst einen gültigen Parameter hinein und erwartest ein korrektes Ergebnis - was mangels Funktionscode noch scheitert. Und schreibst dann die Funktion so, dass auch dieser Test erfüllt wird.  
      
    Jetzt wirst du frivol und schickst im Test einen ungültigen Parameter in die Funktion und erwartest ebenfalls ein für diesen Fall korrektes Ergebnis. Aber was wäre denn ein korrektes Ergebnis für einen ungültigen Parameter? Und was ist überhaupt ein ungültiger Parameter?  
      
    Es ist ja nicht so, dass es in PHP einen Unterschied macht, ob man x=10 oder x='10' hat. Beide Variablen werden in Rechnungen als Zahl und in Stringoperationen als String behandelt werden. Man muß also nicht wirklich prüfen, ob man es wirklich mit einem Integer zu tun hat, wenn diese Frage keine Rolle spielt, oder vernachlässigbar ist, weil sie zu keinem Fehler führt.  
      
    Es wäre also in den Tests kein Problem, wenn vier Szenarien geprüft werden:  
    1\. Integer 10  
    2\. Integer 0  
    3\. String '10'  
    4\. String 'xyz'  
      
    Für alle diese geprüften Fälle muß es definierte Resultate geben. Vielleicht ist Integer 0 der im Zahlenbereich unerlaubte Fall. Dann würde schon automatisch auch 'xyz' behandelt werden, weil dessen Zahlwert auch 0 ist. Oder es kommt darauf an, Integer von Strings zu unterscheiden - was genau Sache ist, hängt ja extrem von der zu lösenden Aufgabe ab.  
      
    Im übrigen ergeben sich weitere zu schreibende Tests für Testfälle in der Regel durch entdecktes Fehlverhalten des Gesamtsystems. Wenn im Gesamtsystem der Parameter dieser Funktion sowieso garantiert ein Integer ist (weil Tests einer anderen Funktion das sicherstellen), braucht man das Vorhandensein von Strings in dieser Funktion ja nicht prüfen.  
      
    Und noch ein Wort zu Exceptions: Ich mag sie nicht. Sie trennen Fehlerbehandlung von Normalbehandlung, und das ist durchaus nicht so wundervoll, wie einem oft eingeredet wird. Erst dadurch entstehen nämlich so supertolle Meldungen wie "Ein unbekannter Fehler ist aufgetreten!", der weder dem Benutzer noch dem Programmierer noch irgendwas hilfreiches sagt. Fehlerzustände sollte man nicht "werfen", sondern abfangen und das Beste draus machen. Eine mögliche Definition von "das Beste" wäre beispielsweise ein Flag "ups, die Abfrage ist schiefgegangen, das gelieferte Resultat ist nur hilfsweise zu verstehen", zusammen mit einem gültigen, aber im Sinne des Kontextes "leeren" regulären Ergebnis. Beispielsweise geht die Datenbankabfrage schief. Das Ergebnis ist dann $ok=false, $data=array(). Mit dem Datensatz kann das abfragende Programm mit Sicherheit weiterarbeiten, leere DB-Ergebnisse können ja immer mal vorkommen. Es kann aber auch explizit den Abfrageerfolg ermitteln und dadurch verzweigen und den Fehlerfall vom Benutzer lösen lassen.  
      
     - Sven Rautenberg
    
    -- 
    "Love your nation - respect the others."
    
    1. Und noch ein Wort zu Exceptions: Ich mag sie nicht. Sie trennen Fehlerbehandlung von Normalbehandlung, und das ist durchaus nicht so wundervoll, wie einem oft eingeredet wird. Erst dadurch entstehen nämlich so supertolle Meldungen wie "Ein unbekannter Fehler ist aufgetreten!", der weder dem Benutzer noch dem Programmierer noch irgendwas hilfreiches sagt.

      Grundsätzlich schliesst sich Gonzo da an, allerdings ist es manchmal recht intuitiv selbst Fehler zu werfen, diese sollten aber natürlich nicht "unbekannter Fehler", sondern eher "Fehler beim Export der Textdatei 'x.txt' in Zeile 42: Wert für die gerade importierte Variable 'x' nicht gefunden ('').".

      1. Moin!

        Grundsätzlich schliesst sich Gonzo da an, allerdings ist es manchmal recht intuitiv selbst Fehler zu werfen, diese sollten aber natürlich nicht "unbekannter Fehler", sondern eher "Fehler beim Export der Textdatei 'x.txt' in Zeile 42: Wert für die gerade importierte Variable 'x' nicht gefunden ('').".

        Das Problem mit Exceptions ist: Man kann sie sehr leicht werfen, aber nur schwierig wieder einfangen, würde ich meinen.

        Ist ja auch ganz einfach: Eine Klasse, für I/O mit irgendwas zuständig, stellt fest, dass der I/O-Partner nicht bereit ist. Also: Exception werfen, und die Kontrolle an die aufrufende Instanz zurückgeben, die wird schon für die Fehlerbehandlung zuständig sein und irgendwas machen.

        Aber der faule Programmierer hat nicht dran gedacht, dass der Aufruf der I/O-Routine mehr als einen Ausgang haben kann, nämlich zusätzlich zur normalen Rückkehr auch noch die Exceptions, die geworfen werden können. Und schon nimmt das Unglück seinen Lauf.

        Google findet 1,7 Millionen Dokumente auf der Suche nach "exceptions considered harmful", z.B. dieses hier: http://silkandspinach.net/2005/06/14/exceptions-considered-harmful/, oder dieses: http://www.joelonsoftware.com/items/2003/10/13.html. Die treffen meine Meinung zu Exceptions ganz gut.

        - Sven Rautenberg

        --
        "Love your nation - respect the others."
        1. Google findet 1,7 Millionen Dokumente auf der Suche nach "exceptions considered harmful", z.B. dieses hier: http://silkandspinach.net/2005/06/14/exceptions-considered-harmful/, ... Die treffen meine Meinung zu Exceptions ganz gut.

          “…I consider exceptions to be no better than “goto’s”, considered harmful since the 1960s, in that they create an abrupt jump from one point of code to another. In fact they are significantly worse than goto’s…”

          Das Problem ist m.E. nicht das abrupte Hin- und Herspringen im Code, sondern schlechter Code, der GoTos und Exceptions genutzt hat und beim Betrachter bspw. Hass auslöst oder ausgelöst hat und somit eine feste negative Meinung induziert hat.

          Gonzo findet GoTos und Exceptions - richtig angewandt - gut. Es gibt bspw. schöne Scripts ohne Subroutinen, dafür aber mit vielen GoTos.
          Gonzo schlägt vor individuelle Programmierqualität als gegeben anzuerkennen und dem guten Programmierer so zu sagen alles zu erlauben. Der Anfänger mag gut beraten sein bestimmte Features seiner Entwicklungsumgebung nicht zu nutzen, allerdings ist auch das ein wenig unklar. Der Depp macht immer Mist.

    2. echo $begrüßung;

      Und noch ein Wort zu Exceptions: Ich mag sie nicht. Sie trennen Fehlerbehandlung von Normalbehandlung, und das ist durchaus nicht so wundervoll, wie einem oft eingeredet wird. Erst dadurch entstehen nämlich so supertolle Meldungen wie "Ein unbekannter Fehler ist aufgetreten!", der weder dem Benutzer noch dem Programmierer noch irgendwas hilfreiches sagt.

      Falscher Umgang mit bestimmten Techniken sollte nicht zu ihrer generellen Ablehnung führen. Das führt nur zu "X ist Mist" mit Begründungen wie: "weil die meisten Anwender damit nicht umgehen können". Spricht etwas dagegen, der Exception eine aussagekräftige Meldung und ebensolche begleitende Werte mit auf den Weg zu geben? Ein Exception-Objekt lässt sich im Gegensatz zu Funktionsergebnissen beliebig gestalten. Nicht in jeder Sprache kann man Typen unbeachtet lassen.

      Fehlerzustände sollte man nicht "werfen", sondern abfangen und das Beste draus machen. Eine mögliche Definition von "das Beste" wäre beispielsweise ein Flag "ups, die Abfrage ist schiefgegangen, das gelieferte Resultat ist nur hilfsweise zu verstehen", zusammen mit einem gültigen, aber im Sinne des Kontextes "leeren" regulären Ergebnis.

      Was wäre ein leeres reguläres Ergebnis einer Funktion, die einen Integerwert in voller Bandbreite zurückliefern darf? Du wirst jetzt sicher nicht mit 0 antworten, sonst verweise ich dich auf dein Thermometer-Beispiel. Null/None und dergleichen wäre in einer typsicheren Sprache ebenfalls kein gültiges Ergebnis der Funktion.

      Beispielsweise geht die Datenbankabfrage schief. Das Ergebnis ist dann $ok=false, $data=array(). Mit dem Datensatz kann das abfragende Programm mit Sicherheit weiterarbeiten, leere DB-Ergebnisse können ja immer mal vorkommen. Es kann aber auch explizit den Abfrageerfolg ermitteln und dadurch verzweigen und den Fehlerfall vom Benutzer lösen lassen.

      Und das soll mit mit Bedacht verwendeten Exceptions deiner Meinung nach nicht möglich sein?

      Ich stimme mit dir überein, dass man den nächsten Verarbeitungsschritt  nur mit gültigen leeren Parametern angehen sollte. Man muss ihn aber auch komplett abbrechen können, wenn das Ergebnis unrettbar verloren ist und durch die Default-Werte nur noch falscher wird als es so schon ist.

      echo "$verabschiedung $name";

  4. echo $begrüßung;

    Wie ist das bei PHP5 genau? Muss ich da wirklich IMMER alles prüfen? Ist also sowas unbedingt nötig:
    public function x(int $value)

    Es ist vor allem "nicht möglich", zumindest wenn du skalare Typen verwenden möchtest. Wie das Kapitel Type Hinting offenbart lassen sich nur Klassennamen und array als Type Hint verwenden.

    echo "$verabschiedung $name";