NoFollow Free!
SHIFT Weblog

Dieses Blog ist ein Online-Magazin für erfahrene Website-Entwickler und Webdesigner, die PHP und Webdesign lieben.

PHP

Mein Verständnis von MVC

mvc_v

MVC – diese drei Buchstaben haben es in sich. MVC ist ein Design Pattern, eine strukturelle Lösung für Entwickler. Kaum ein anderes Design Pattern löst so viel Kontroverse aus und regt zu endlosen Diskussionen an – zumindest in der PHP-Welt.

Das liegt daran, dass MVC recht oberflächlich beschrieben wird, und möchte man sämtliche MVC-Erklärungsversuche zusammenfassen, so ist man schnell der Auffassung:

  • Model (M) : Die Verbindung zur Datenbank
  • View (V) : Die Ausgabe an den Benutzer
  • Controller (C) : Der Verwalter zwischen den Schichten

Die Wahrheit ist aber: Es ist viel mehr als das. Der große Fehler, den MVC-Neulinge dabei begehen, ist, ihr Projekt nur nach diesen Gesichtspunkten zu gestalten. Oft wird übersehen, dass MVC nur eines von mehreren Zahnrädern in einer ganz anderen Schichtenarchitektur ist: Der Präsentationsschicht, der Logikschicht (auch als Businessschicht bezeichnet) und der Persistenzschicht. MVC agiert in allen drei Schichten, hauptsächlich jedoch in der Präsentationsschicht. Verfolgt man MVC-Diskussionen in gängigen Foren, kommt erschwerend hinzu, dass jeder MVC etwas anders auslegt. Es gibt also nicht selten kein “richtig” oder “falsch”. Die Grenzen, die MVC versucht aufzuzeigen, scheinen paradoxerweise ineinander zu verschwimmen.

Ich versuche, mit diesem Artikel dem Verständnis von MVC auf die Sprünge zu helfen, ich betone aber, dass dies nur meine Auffassung des Patterns ist. Ich möchte daher nicht deutlich machen, dass meine Ansicht die richtige oder die falsche ist – es ist eher ein mögliches Konzept zur strukturellen Realisierung von MVC. Außerdem liefere ich hier kein MVC-Tutorial, die allgemeine Funktion des Patterns sollte bekannt sein.

Bevor es ans Eingemachte geht, möchte ich mit einige Statements kommentieren, die man oft in MVC-Tutorials findet.

MVC ist nur in objektorientierter Umgebung möglich

So eine Aussage ist schlichtweg falsch. Diese Aussage rührt mit Sicherheit daher, dass viele PHP-Frameworks, die MVC benutzen, ebenfalls auf OOP setzen. Hierzu möchte ich klar stellen, dass MVC theoretisch auch in prozeduraler Umgebung realisierbar ist. Objektorientierte Verwirklichungen stellen unterschiedliche Elemente der MVC-Struktur aber besser bzw. logischer dar.

MVC ist für Desktop-Anwendungen erdacht; für Web-Applikationen ist MVC fehl am Platz

Das ist einerseits richtig, andererseits aber auch falsch. Das Design-Pattern entsprang im Kontext von Programmiersprachen, die sich in erster Linie an Desktop-Applikationen richten. MVC wurde beschrieben, als es das Internet, wie wir es heute kennen, noch gar nicht gab. Trotzdem ist MVC durchaus auf Web-Anwendungen portierbar, auch wenn Detailpunkte etwas anders ausgelegt werden müssen.

MVC schreibt Regeln vor, die eher behindern als weiterhelfen

Das ist eine recht subjektive Betrachtungsweise, die aber oft geäußert wird, wenn nicht weit genug gedacht wird: Regeln in der Programmierung sind ungemein wichtig. Das EVA-Prinzip etwa ist ebenfalls eine Regel, an die sich jeder gute Programmierer halten sollte. Bei diesem Prinzip ist der Vorteil schnell erkannt, bei MVC jedoch fehlt anfänglich oft das Verständnis für dass Trennen der Strukturen.

Warum MVC?

Folgt ein Projekt dem MVC-Pattern, so hat dies mehrere Vorteile. Zum einen ist eine Grundvoraussetzung zur Trennung verschiedener Strukturen geschaffen. Stellt euch als Beispiel eine Tabelle einer Datenbank vor, in der Benuter gespeichert sind. Diese werden zunächst in einer HTML-Tabelle ausgegeben. Nun wird aber die Aufgabe erteilt, die Daten der Datenbank als XML auszugeben. Unter Berücksichtigung von MVC ist diese Aufgabe mit geringem Einsatz zu lösen, da nur an wenigen Stellen etwas geändert werden muss: Die eigentliche Abfrage bleibt unberührt, auch der verarbeitende Teil der Benutzereingaben (sofern vorhanden) muss nur um die XML-Generierung geändert werden.

Der andere Aspekt ist die Wiederverwendbarkeit. Ein Model oder eine View sind darauf ausgelegt, an verschiedenen Stellen benutzt zu werden. Ein Beispiel dafür könnte eine Tagcloud sein, wie man sie etwa aus WordPress kennt.  Sie fungiert im Frontend anders als im Backend: Im Backend dient sie zum Definieren von Tags beim Erstellen eines Blogartikels, im Frontend dient sie zum Anzeigen diverser Artikel, die das angeklickte Tag beinhalten. Das Aussehen dieser Tagcloud ist jedoch immer das gleiche und es macht Sinn, das Aussehen der Tagcloud nur einmal zu definieren.

Wie funktioniert MVC?

Die Liste, die oben genannt wurde, ist nur in grober Betrachtung richtig. Der Ablauf erfolgt, zusammengefasst, folgendermaßen: Anhand diverser Parameter (die normalerweise via URL bestimmt werden) wird ein Controller geladen. Dieser Controller hat nur eine Aufgabe: Die auszuführende Aktion abzuschließen und dem Browser eine Antwort zu liefern, die für gewöhnlich in Form eines HTML-Markups erfolgt. Für diese Aufgabe hat der Controller zwei Werkzeuge zur Hand: Die View sowie (ein oder mehrere) Models. Die Models repräsentieren einen bestimmten Abschnitt aus einer Datenbank oder einem anderen nicht-flüchtigen Speicher. Die View ist ein Grundgerüst, dass vom Controller nur noch mit Daten befüllt werden muss. Diese Daten können aus einem Model stammen. Abschließend generiert der Controller die Ausgabe.

Für diesen Ablauf sind jedoch Komponenten notwendig, die mit MVC aber nicht zwingend was am Hut haben. Dazu komme ich später. Wichtig ist zu erkennen, dass

  1. der Controller keineswegs ein Alleskönner ist, dem sämtliche Aufgaben zur Last gelegt werden. Vielmehr handelt es sich um eine Struktur, die delegiert. Sie delegiert nicht nur  zwischen View und Model, sondern kann auch auf andere Elemente zugreifen, etwa die Konfigruation der Applikation, dem Ergebnis des Routings oder aber einer Validator-Klasse um Benutzereingaben zu validieren
  2. das Model keine Kenntnis von der Datenbank hat und dementsprechend auch keine Verbindung zu dieser hat
  3. die View größtenteils aus Markup besteht und nur in geringem Umfang PHP-Strukturen enthält

Diese drei wichtigen Punkte werde ich nun etwas näher erläutern.

MVC im Detail

Das Model

In Foren hatte ich den Eindruck, dass hier ein großer Diskussionsbedarf besteht. Ein Model repräsentiert lediglich einen bestimmten Abschnitt aus einem nicht-flüchtigen Speicher. Es hat keine Verbindung zur Datenbank. Dem Model ist es piepegal, woher es die Daten hat. Es stellt lediglich Schnittstellen (Methoden) zur Verfügung, um auf die gespeicherten Werte zuzugreifen. Jetzt fragt sich der MVC-Neuling sicher: “Woher kommen denn die Daten, wenn das Model sie nicht kennt?”. Hierfür gibt es Repositories. Ein Repository ist die konkrete Schnittstelle zwischen Model und dem Speicher. Ein Repository stellt Methoden bereit, um gewisse Datensätze abzugreifen, Datensätze zu löschen oder zu aktualisieren. Im Falle einer Datenanfrage werden die gefundenen Datensätze in einer Kollektion von Models zurückgegeben (überlichweise in einem Array oder einem ArrayObjekt). Ein Model repräsentiert immer ein zusammenhängendes Element des Speichers (beispielsweise eine Tabellenzeile aus der Datenbank).

Da dies recht viel Information auf einmal ist, hier ein wenig Code, der eine beispielhafte Implementation von Model und Repository darstellt:

$user = $userRepository->find(56);  // Benutzer mit ID 56 holen
echo $user->getName();              // Ausgabe des Benutzernamens
$user->setBirthday(new DateTime('1985-03-28')); // Aktualisieren
$userRepository->persist($user);    // Änderungen speichern

Die View

Die View enthält die Daten, die später der Ausgabe dienen. Im Gegensatz zum Model und zum Controller besteht die View meistens nur zu einem kleinen Teil aus PHP-Code. Vielmehr ist es das HTML-Markup (oder eine andere Ausgabeform), das eine View auszeichnet.

Internetseiten haben die Eigenschaft, dass sie, egal auf welcher unterseite einer Applikation man sich befindet, immer eine hohe Prozentzahl an gleichem HTMl-Code beinhalten. Der gesamte HEAD-Bereich des Markups unterscheidet sich oft nur gering, Header und Footer sind oft immer identisch, und das einzige, was sich typischerweise ändert, ist der Inhaltsblock. Es macht also sinn, Views so zu gestalten, dass sie mit Abschnitten vorbelegt sind und nur noch mit Werten befüllt werden müssen, die sich auf den Unterseiten ändern. Führt man diesen Gedanken fort, so ist das Verschachteln von Views unumgänglich. Der folgende Code zeigt eine beispielhafte Implementation von verschachtelten Views.

$view = new View('layout');
$view->title = 'Hallo, Welt!';
$view->sidebar = new View('widget'); // Verschachtelung
$view->sidebar->title = 'Eine Sidebar';
echo $view->render();

Die View agiert passiv. Sie stellt keine Anfragen oder enthält keine Verarbeitungsrelevanten Elemente. Manchmal sehe ich, dass eine View direkten kontakt zu einem Repository aufnimmt oder in der Lage ist, ein Model zu instanziieren. Das ist in meinen Augen jedoch grundsätzlich falsch und widersprecht meinem Prinzip “Die View ist dumm und nimmt eine passive Rolle im Pattern ein”.

Der Controller

Der Controller ist nicht nur die vermittelnde Instanz zwischen Model und View. Der Controller ist in der Lage, Models anzufragen, um diese entweder intern weiterzuverarbeiten oder an die View weiterzuleiten. Der Controller darf auch andere Klassen ansprechen, die ihm bei diesem Vorgehen behilflich sind oder Teil der derzeit auszuführenden Aktion sind: Das Laden eines Validierers, das Ansprechen eines Loggers oder das Senden einer E-Mail ist da beispielsweise zu nennen. Ein Projekt enthält üblicherweise mehrere Controller. Wie diese Controller zu trennen sind, ist nicht fest definiert. Wichtig ist, dass man Aufgaben in der Applikation gruppiert und dann Themenbereiche bildet, die in unterschiedlichen Controllern abgebildet werden können. Ein Controller könnte für die Benutzerauthentifizierung zuständig sein, ein anderer etwa für das Erstellen und Verwalten eines Blogeintrages.

Der Controller selbst stellt mehrere Actions bereit, die zum Themengebiet des Controllers passen. Der fiktive Controller Authentication könnte etwa die Actins “Login”, “Logout”, “Forgot_Password” oder “Register” bereitstellen. Analog könnte man sagen: Actions sind Methoden, Controller sind die Klassen. Eine Controllerklasse wird instanziiert, wenn sie (etwa wie URL) dazu aufgerufen wird.

Zur Vollständigkeit halber sei gesagt, dass es auch möglich ist, dass ein Controller einen anderen Controller aufruft. In diesem Fall spricht man von HMVC (Hierarchial MVC) oder modularisiertes MVC, ich möchte aber nicht näher darauf eingehen.

Wenn wir uns nun diese Aufgabenverteilung verinnerlichen, so könnte man das klassische Schema von MVC noch etwas abändern, um für mehr Klarheit zu sorgen. Allgegenwärtig ist dieses Schema:

Einfaches MVC-Modell

Etwas deutlicher wird es schon mit diesem Schema:

Der Controller kann mehrere Actions beinhalten. Eine Action hat nur mit Repositories Zugang zu einem oder mehreren Models. Die View wird vom Controller erstellt, kann mit Models oder anderen Daten bestückt werden und ist zudem verschachtelbar.

Vereinfachtes Austauschen von Komponenten

Erst jetzt wird vielleicht klar, welche Stärke MVC hat: Das Auslagern von bestimmten Applikationselementen hat den Vorteil, dass Grundstrukturen ohne Komplikationen ausgetauscht werden können.

Angenommen, in einem großen Projekt werden an vielen Stellen Daten aus einem Model ausgegen. Diese Daten hat das Model aus einer Datenbank. Nach einer Umstrukturierung sieht der Plan vor, dass einige Dateninhalte künftig aus einer XML-Datei kommen. MVC sieht vor, dass sich in diesem Fall das Model nicht ändert (zumindest nicht die Methoden zur Abfrage der Daten). Das, was ausgetauscht wird, ist das Repository. An nur einer einzigen Stelle. Ohne MVC hätte es ein großes Durcheinander gegeben, weil der Code an jeder Stelle, wo die Daten aus der Datenbank ausgegeben wurden, im großen Stil abgeändert werden müsste.

Ebenso das Zusammenspiel von Controller und View sorgt dafür, dass einzelne Elemente wiederverwendbar werden. Stellt euch ein Formular für Mitglieder eines Forums vor, dass dafür da ist, Benutzerdetails (etwa Wohnort, E-Mail-Adresse usw) zu ändern. Das Ausgeben des Formulares (nicht die Verarbeitung!) ist Teil der View. Ein Administrator des Forums soll ebenfalls die Möglichkeit haben, Details von angemeldeten Benutzern zu ändern. Für diesen Zweck kann die gleiche View verwendet werden (und ggf. um einige Formularfelder erweitert werden).

MVC als Teil einer Gesamtstruktur

Ich habe oben schon kurz angedeutet, dass MVC nicht die Struktur eines ganzes Projektes wiederspiegelt. MVC ist Teil einer Struktur, die aus drei Schichten besteht:

  • Präsentationsschicht
    Die Präsentationsschicht enthält sämtliche Elemente, die für die Ausgabe der Applikation zuständig sind. Dazu gehört HTML-Markup, aber auch etwa eine Klasse, die Rückgabewerte für einen Ajax-Request formuliert. Weite Bereiche von MVC  gehören in diese Schicht
  • Logikschicht (oder Businessschicht)
    Innerhalb der Logikschicht passiert alles, was für die Verarbeitung bestimmt ist. Dazu zählt etwa die Validierung von Benutzereingaben, das Session Handling oder ein Autoloader.
  • Persistenzschicht
    Alle nicht-flüchtigen Daten sind Teil der Persistenzschicht. Dazu gehört eine Konfigurationsdatei, die Datenbank oder auch Cookies.

Ich habe mal ein weiteres Schema erstellt, in dem alle MVC-Komponente als Teil der Gesamtstruktur eingegliedert werden. Außerdem enthält es einen groben Ablaufplan (vom Request zum Response), was sicherlich hilfreich ist, wenn man ein eigenes Framework plant oder ein bestehendes versucht nachzuvollziehen.

MVC als Teil einer Gesamtstruktur

Die weißen Rechtecke sind MVC-Komponente, die grünen Kreise PHP-interne Funktionalität und gelbe Bereiche sind Klassen, die für den Betrieb der Applikation erforderlich sind. Dieses Schema ist keineswegs vollständig, es enthält lediglich übliche Komponente und soll helfen, häufig benutzte Elemente einzuordnen.

Fazit

MVC ist schnell erklärt, aber die Auslegung der Regeln sowie das Einordnen verschiedener Komponenten ist häufig immer wieder unterschiedlich. Ich betone noch einmal: Die Erklärungen in diesem Artikel spiegeln lediglich mein Verständnis von MVC wieder. Ich beschrieb es, wie ich es auffasse und umsetze. Für jeden, der sich über die Strukturierung noch nicht ganz sicher ist, findet mit diesem Beitrag vielleicht eine kleine Stütze.

 

Kommentare

Auf dieses Thema gibt es 11 Reaktionen

  1. Vargson

    Guter Artikel,

    vor allem für Programmierer, die Probleme beim Aufbau bzw. der Strukturierung einer Anwendung haben. Für mich persönlich aber nichts neues.

    Wann kommt denn die Beta von deinem FW?

    Gruß

    • Huhu,

      danke für das Lob. ich setze mir kein Ziel für mein Framework. Ich habe Mitte 2011 damit begonnen, von vorne anzufangen, was eine sehr gute Entscheidung war, aus meiner Sicht. Außerdem arbeite ich mich gerade in Unit Tests ein, die bei meinem FW nicht fehlen dürfen. Wenn du willst, schicke ich dir mal einen Link zum Repository, wenn dich der Zwischenstand interessiert.

  2. Zeichen32

    Hey ho,
    wirklich guter Artikel zum Thema MVC und den Einstieg in dieses Konzept. Deine Ansicht zu diesem Design Pattern spiegelt meine recht gut wieder, weshalb ich auch schon gespannt auf die erste Version deines FW bin. ;)

    Also weiter so!
    Zeichen

    @PS: Auf dem iPhone liegt das Shift Logo etwas nervig immer über dem Text der Seite.

  3. Schöne Zusammenfassung. Ich persönlich halte es so, wie Yii es ursprünglich mal empfohlen hat, d. h. ich habe wechselnde Modelle für Formulareingaben und wechselnde Modelle für Datenbankabfragen. Diese Modelle ändern sich auch, je nach Anforderungen oder es kommen auch schon mal welche dazu.

    Ansonsten habe ich sehr viele fertige Modelle für Sonderfunktionen wie PDF Generierung, E-Mailen, Passwörter, Auth, usw, die sich kaum mal ändern.

    Ich finde es auch idiotisch, da zu pedantisch zu sein und alles in (meist) statische Klassen zu schreiben, wo es auch Funktionen tun. Das bringt keine Performancevorteile und erst recht nicht mehr Übersicht. Im Gegenteil: Häufige Funktionen wie die Ausgabe von Hyphenation läuft bei mir einfach mit einer Funktion _h(), anstatt $extension::hyphenation().

  4. mario

    Schöner Artikel. Endlich mal ein wenig tiefgründiger erörtert. Dennoch klingt es wieder ziemlich nach Faux MVC. Insbesondere scheint das Model ja wieder nur als passives Backend betrachtet zu werden, und der Controller ist in wirklichkeit wieder Orchestrator oder Presenter. Klingt eher nach passivem MVP.

    Wer halbewegs reales MVC im Web implementieren will, sollte sich eher an View=HTML+JS, Controller=AJAX, Model=PHP orientieren.
    http://stackoverflow.com/questions/1549857/simple-php-mvc-framework/1549970#1549970

    • Der verlinkte SO-Beitrag gefällt mir. Der Ersteller hat mit dem, was er sagt, prinzipiell Recht. Auch ich bin in meinem Artikel hier darauf eingegangen, behaupte aber trotzdem, dass MVC auch in der statuslosen HTTP-Welt funktioniert. Es ist eben nicht mehr mit dem MVC vergleichbar, was bei Desktopanwendungen angewandt wird.

      Du nennst meine Interpretation “Faux MVC” oder “passives MVP” – aber genau das ist ja das Dilemma, das MVC im Web so undurchsichtig macht – jeder interpretiert das Pattern eben anders.

      Eine Lösung, MVC mit Hilfe von Ajax nachzubilden, halte ich für falsch, da hier zwei Technologien vermischt werden: Die serverseitige und die clientseitige. Das an sich wäre kein Problem, jedoch kann man sich auf die clientseitige Unterstützung niemals 100% verlassen (… da es leider immer noch Anwender gibt, die JS deaktiviert haben. Aber das ist ein anderes Thema).

  5. MAX

    Sehr schöner Beitrag, danke.
    Ich lese gerne deine Beträge nur leider sind es in letzter Zeit nur sehr wenige.

    • Danke für das Feedback,

      ja in der Tat sind hier nur sehr unregelmäßig Beiträge zu erwarten. Das liegt zu einen daran, dass ich sehr wenig Zeit habe und meine Arbeit mich ungemein einspannt. Zum anderen schreibe ich gerne über mir persönlich wichtige Dinge, über die in anderen Blogs noch nicht viel gesprochen wurde. Bei mir geht also Qualität vor Quantität :)

      LG

  6. Das ist wirklich ein klasse Artikel! Super erklärt und ordentlich bebildert.

    Ich denke das Problem ist, dass MVC zwar ein Muster beschreibt, die Umsetzung von vielen jedoch schwammig ist. Meist liegt es an falschem Verständis, oft auch an Faulheit/Zeitersparnis :-)

    RSS-Feed ist abonniert :-)

Hinterlasse eine Antwort

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *

*

Du kannst folgende HTML-Tags benutzen: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">

 

Weitere Artikel der Kategorie PHP

PHP

Ausnahmezustand: PHP und Exceptions

Mit PHP 5 wurde dem Entwickler ein Werkzeug zur Verfügung gestellt, dass es in anderen objektorientierten Sprachen wie C++ und Python schon lange gibt: Exceptions. Mit diesen hat der Entwickler die Möglichkeit, auf ungewollte Ereignisse zu reagieren. Exceptions werden “geworfen”, das bedeutet, sie unterbrechen den normalen Programmfluss und behandeln eine eventuelle Ausnahme, die den weiteren

Weiterlesen ›

PHP, Quickies

Snippet: Geldbeträge mit PHP bereinigen

Folgendes Szenario: Ein Benutzer einer PHP-Applikation muss einen Geldbetrag eingeben. Für die Weiterberechnung und Speicherung dieses Betrages erwartet PHP ein Format wie 123 oder 567.89, nicht aber 246,80 oder 500,-. Bevor dem Benutzer der Applikation lange Erklärungen geben, wie eine solche Eingabe auszusehen hat, sollten wir uns selbst um die Bereinigung der Geldbetrageingabe kümmern. Wenn

Weiterlesen ›

PHP, Webdesign

This is not sexy: PHP-Template-Engines á la Smarty

Nachdem ich mich in der Vergangenheit über das Zend Framework, Flash und CSS Frameworks ausgelassen habe, ist es mal wieder an der Zeit, den Buhmann zu spielen und möchte mich hier nun über einige PHP-Template-Engines aussprechen. Stellvertretend für viele dieser Projekte werde ich im laufe des Artikels “Smarty” nennen – ich glaube, dass dieser Name

Weiterlesen ›