Sven Rautenberg: MVC - Theorie

Beitrag lesen

Moin!

Ein Interface wäre an dieser Stelle als Alternative für eine abstrakte, codelose Klasse eindeutig vorzuziehen. Und (das ist das I von SOLID) eine Klasse kann mehr als ein Interface implementieren, es ist also möglich und angeraten, keine Mega-Interfaces zu schreiben, sondern für die jeweils beabsichtigten Funktionen ein möglichst kleines Interface vorzusehen.

Du meinst also ich sollte ein Datenbank-Interface schreiben?
Ich muss gestehen, dass mir nicht ganz klar ist wozu Interfaces in PHP gut sind. Für mich sieht es so aus, als ob sie nur Funktionsnamen bereit stellen. Das erscheint mir aber überflüssig weil ich die Funktionen eh schreiben muss, das Interface also auch weglassen könnte.

Ich würde es mal so formulieren (und hole dabei etwas weiter aus):

Angenommen, du schreibst eine Klasse. Und dann schreibst du noch eine zweite Klasse, die fast genau dasselbe tut, nur in manchen Details halt anders. Diese zweite Klasse kopiert den Code der ersten meistens.

Dann ist die logische Konsequenz: Der gemeinsame Code kommt in eine Elternklasse, und die jeweiligen Abweichungen jeder einzelnen Klasse bleiben halt dort. Dabei ist möglichst viel gemeinsamer Code in die Elternklasse zu packen.

Und wenn die Elternklasse für sich allein nicht instanziiert werden kann, weil ihr zur Funktionsfähigkeit eben genau jene Methoden fehlen, die in den Kindklassen die Details regeln, dann macht man die Elternklasse abstrakt, und auch ein paar der jeweiligen Methoden.

Im Typehinting von anderen Methoden kann man jetzt aber diese abstrakte Elternklasse als geforderten Typ des Parameters angeben. Die Konsequenz ist, dass man dort ein Objekt entweder des einen oder anderen Kindes der Elternklasse übergibt, denn die Elternklasse ist ja abstrakt.

Nun kann es aber vorkommen, dass man zwar gern ein Typehinting für Objekte bestimmter "Abstammung" hätte, es allerdings keinen Sinn ergibt, eine abstrakte Klasse zu bauen, weil es keinen gemeinsamen Code gibt. Für solch einen Fall kann man mit einem Interface ebenfalls sicherstellen, dass die Objekte, die das Interface instanziieren, alle damit definierten Methoden implementieren - aber eben ohne gemeinsamen Code. Nur mal als Anregung, warum Klassen, die dasselbe tun, nicht denselben Code verwenden könnten: Die DB-Klassen für MySQL und PostgreSQL benutzen jeweils die nativen Funktionen - da kann man kaum identischen Code finden und auslagern.

Interfaces erlauben also, Klassen gleicher Funktion zu identifizieren, ohne dass ihr Code eine gemeinsame Abstammung haben muss aufgrund vererbten Codes. Man kann Interfaces sogar rein als Kennzeichnung ohne jegliche geforderte Methoden schreiben und implementieren, um nur diesen Identifizierungseffekt zu benutzen, allerdings würde ich persönlich das nur im Ausnahmefall wirklich tun. Ich finde es beispielsweise wenig sinnvoll, dass jede existierende Klasse mit Chance auf Duplizität automatisch gleich so ein Tagging-Interface implementiert, in dem keine Methoden definiert werden. Das ist OOP-Overkill.

Als gute Ideengeber würde ich mal die Interfaces der SPL nennen: ArrayAccess definiert vier Methoden, Iterator definiert fünf, und Countable sogar nur eine einzige. Die Kombination aller drei Interfaces erlaubt es, dass ein Objekt sich vollkommen wie ein Array verhalten kann, man aber volle Kontrolle über den Zugriff auf die internen Daten behält.

Siehe oben, mir ist nicht ganz klar wozu man da ein Interface braucht.

Diese Interfaces haben, im Gegensatz zu denen, die du selbst definieren kannst, noch eine Spezialbedeutung:

Implementierst du das Interface "ArrayAccess", dann kannst du mit der Array-Schreibweise auf die von dir gewünschten Werte deines Objekts zugreifen:

class accessTest implements ArrayAccess {  
// Hier die Methoden  
}  
  
$einArray = new accessTest();  
$einArray['name'] = 'wert';  
echo $einArray['name'];  
echo get_class($einArray); // ergibt "accessTest"  

Diese Zugriffsform wird von PHP intern realisiert, indem die Array-Schreibweise in Aufrufe der vom Interface geforderten Methoden gemappt wird. Gleiches gilt für die Implementierung von "Iterator" - damit kannst du ein Objekt mittels foreach() durchgehen. Und "Countable" erlaubt, die Funktion count() auf das Objekt anzuwenden. Alle drei Interfaces realisieren Teilaspekte von dem, was man mit einem echten Array machen kann, aber wie erwähnt: Es ist ein Objekt, man kann eigenen Code ausführen, um Einfluss zu nehmen.

Deine Ausführung zu Tests muss ich mir nochmal durchden Kopf gehen lasse. Ich habe nicht ganz verstanden was du mir damit sagen wolltest.

Da möchte ich dich einfach mal weiterverweisen: http://www.lastcraft.com/simple_test.php und http://www.lastcraft.com/first_test_tutorial.php sind die nach meiner Meinung sehr gut geschriebenen Seiten, die als Einführung in Unittests gelten dürften.

Einen Nachteil haben diese Seiten: Das dort erwähnte Test-Framework "SimpleTest" ist leider hoffnungslos veraltet, es supportet noch PHP 4 und nutzt deshalb selbst noch keine Features von PHP 5. Der Platzhirsch an dieser Stelle ist eindeutig "PHPUnit". Aber die Prinzipien der beiden Frameworks sind absolut vergleichbar, deshalb ist es keine vertane Zeit, wenn du dir die zwei Links mal zu Gemüte führst.

- Sven Rautenberg