Melvin Cowznofski: OOP im MCV Stil mit PHP

Hallo,

nachdem ich meine PHP Skripte jahrelang im prozeduralen Stil geschrieben hatte, bin ich irgendwann umgestiegen auf eine objektorientierte Programmierung. Allerdings waren 99% meiner Methoden statisch, benötigten also keine Klasse. Und somit war das Konzept von OOP nicht wirklich in Verwendung.

Ich denke, dies ist der typische "Anfängerfehler", wenn man mit OOP beginnt. Da wird dann einfach alles in Klassen geschmissen und statisch aufgerufen. Naja, das hat, obwohl das dann ja nichts anderes als eine Funktions-Sammlung ist, dann zumindest den Vorteil, dass die Methoden thematisch strukturiert in Klassen zusammengefasst sind.

Diesen Stil habe ich jedenfalls geändert, nachdem ich immer mehr verstanden habe, was die Vorzüge einer wirklichen OOP sind, und arbeite nun eigentlich überhaupt nicht mehr mit rein statischen Methoden. Allerdings hatte ich bisher so gut wie immer sämtlichen Code für ein gewünschtes Prozedere in einer einzigen Methode verpackt. Und als ich in letzter Zeit mehrmals mit dem Begriff des MCV Modells konfrontiert wurde, war mir klar, dass mein Programmierstil dem offensichtlich nicht entspricht.

Ich habe mich jetzt eine Zeit lang mit dieser Pattern-Idee beschäftigt und hoffe, das nun halbwegs verstanden zu haben. Am Anfang fand ich dieses Konzept etwas verwirrend. Aus diesem Grund schreibe ich dieses Posting. Ich würde gerne wissen, ob ich das Konzept richtig verstanden und anhand eines Beispiels auch richtig umgesetzt habe.

Nehmen wir als völlig triviales und sinnloses Beispiel, dass 2 Strings mit einem Verbindungs-String zu einem einzigen String verkettet werden sollen. Mein Lösungsansatz mit OOP und angewandtem MCV Modell sieht folgendermaßen aus:

Bei der Instanz-Erstellung wird der Klasse ein gewünschter Verbindungs-String übergeben. Es muss also ein neues Objekt erstellt werden, wenn sich der Verbindungs-String ändern soll. Wenn nichts übergeben wird, dann soll standardmäßig ein Bindestrich mit einem Leerzeichen links und rechts davon die beiden String-Teile verbinden.

Die Methode change() ist ein Controller. Sie nimmt den Auftrag vom User entgegen und leitet ihn an das Model, die Methode stringManipulation() weiter. Diese Methode macht nun die eigentliche Arbeit. Das Resultat wird als Eigenschaft des Objekts gespeichert. Die Methode showManipulation() ist der View-Teil des Modells. Sie stellt das Ergebnis zur Verfügung, in dem sie die Eigenschaft abholt und an den Controller zurückgibt. Dieser kann nun das Ergebnis an den User zurückgeben.

Das Model, die Methode stringManipulation() hat hier nur diese eine Aufgabe, könnte aber auch andere Arbeiten verrichten, wie zB. das Kürzen von Strings. Deshalb übergibt man ihr mittels dem Wert $order den genauen Auftrag.

Der gesamte Code samt 2 Ausgaben sieht nun so aus:

<?php

declare(strict_types = 1);
header('content-type:text/html; charset=UTF-8');
error_reporting(E_ALL|E_STRICT);
mb_internal_encoding('UTF-8');

// Ziel: Methode change() der Klasse Stringmanipulation soll 2 Strings mit einem anderen String verbinden.

class Stringmanipulation
{

private $_connector;
private $_manipulationResult;

public function __construct(string $connector = ' - ')
	{
		$this -> _connector = $connector;
	}

// Controller:
public function change(string $input_1, string $input_2): string
	{
		$this -> stringManipulation($input_1, $input_2, 'connect');
		return $this -> showManipulation();
	}

// Model:
private function stringManipulation(string $input_1, string $input_2, string $order)
	{
		if($order === 'connect')
			{
				$string = $input_1.$this -> _connector.$input_2;
				$this -> _manipulationResult = $string;
			}
	}

// View:
private function showManipulation(): string
	{
		return $this -> _manipulationResult;
	}

}

$manipulation_1 = new Stringmanipulation;
echo $manipulation_1 -> change('Mann', 'Frau').'<br><br>';
$manipulation_2 = new Stringmanipulation('#####');
echo $manipulation_2 -> change('Mann', 'Frau');

?>

Ich würde jetzt gerne wissen, ob das (abgesehen von der Unsinnigkeit der Aufgabe) ein korrektes Umsetzen des MCV Modells mit OOP ist, damit ich weiß, ob ich die Sache jetzt halbwegs richtig verstanden habe. Mir ist klar, dass man für diese Aufgabe so ein Konzept nicht wirklich braucht. Es geht mir rein um die logisch richtige Anwendung des Programmier-Patterns.

Wo ich mir prinzipiell nicht sicher bin, ist die Entscheidung, wann man jetzt das MCV Modell verwenden soll und wo es unsinnig ist. Da geht es mir wie mit den statischen Methoden in Klassen. Ich verwende sie eigentlich überhaupt nicht mehr, auch nicht in Fällen, wo ich mich frage, ob das Erstellen eines Objekts, nur damit man eine Methode verwenden kann, nicht "too much" ist. Auch hier fällt mir dann die Entscheidung schwer, ob ich jetzt eine Instanz erstellen und die Methode nicht-statisch mache oder nicht. Ich würde mich freuen, wenn mir hier jemand, der sich mit dieser Thematik besser auskennt, ein kleines Feedback oder einen Input gibt, egal, ob technischer oder philosophischer Natur.

Mit lieben Grüßen

Melvin Cowznofski

PS: Übrigens: Hello again! Ich war hier jahrelang nicht mehr online. Ein schönes Gefühl, wieder mal aktiv zu sein hier!

--
What – me worry?
  1. Lieber Melvin,

    PS: Übrigens: Hello again! Ich war hier jahrelang nicht mehr online. Ein schönes Gefühl, wieder mal aktiv zu sein hier!

    welcome back!

    Kann es sein, dass Du nicht MCV, sondern MVC meinst? Leider kann ich Dir dazu keine Hilfe anbieten, da ich es selbst weder nutze, noch begriffen habe.

    Liebe Grüße

    Felix Riesterer

    1. Hallo Felix,

      ja, Du hast Recht, natürlich meinte ich MVC. Ich hatte wohl zu schnell geschrieben. Geschwindigkeitsbedingte Legasthenie sozusagen. 😏

      Mit lieben Grüßen

      Melvin Cowznofski

      --
      What – me worry?
    2. @@Felix Riesterer

      Kann es sein, dass Du nicht MCV, sondern MVC meinst?

      Eselsbrücke: MelVin Cowznofski

      🖖 Stay hard! Stay hungry! Stay alive! Stay home!

      --
      Home Office ist so frustierend, weil man jetzt noch viel stärker bemerkt mit wievielen Menschen man zu tun hat, die nicht sinnerfassend lesen können. (@Grantscheam)
  2. Tach!

    Ich würde jetzt gerne wissen, ob das (abgesehen von der Unsinnigkeit der Aufgabe) ein korrektes Umsetzen des MCV Modells mit OOP ist, damit ich weiß, ob ich die Sache jetzt halbwegs richtig verstanden habe. Mir ist klar, dass man für diese Aufgabe so ein Konzept nicht wirklich braucht. Es geht mir rein um die logisch richtige Anwendung des Programmier-Patterns.

    MVC ist ein Model für ein Framework. Dein Beispiel ist lediglich ein Anwendungsfall für einen Service.

    dedlfix.

    1. Hallo dedlfix,

      auf Wikipedia steht:

      Ein Framework gibt somit in der Regel die Anwendungsarchitektur vor.

      Und als genau das habe ich es betrachtet. In Tutorial Videos auf YouTube ist mir immer wieder untergekommen, dass sich diese Programmier-Logik, oder wie immer man das jetzt auch nennt, bei komplexeren Skripten anbietet.

      MVC ist ein Model für ein Framework.

      Also ich hatte das so verstanden, dass dies auch einfach eine Art ist, wie man (besseren) Code schreiben kann.

      Dein Beispiel ist lediglich ein Anwendungsfall für einen Service.

      Das mag schon sein, mir ging es prinzipiell nur darum, diese 3 Teile richtig voneinander getrennt zu haben.

      Mit lieben Grüßen

      Melvin Cowznofski

      --
      What – me worry?
      1. Tach!

        In Tutorial Videos auf YouTube ist mir immer wieder untergekommen, dass sich diese Programmier-Logik, oder wie immer man das jetzt auch nennt, bei komplexeren Skripten anbietet.

        Eher nein, man braucht schin die Größenordnung einer Anwendung, um ein auf MVC basierendes Framework sinnvoll einzusetzen.

        MVC ist ein Model für ein Framework.

        Also ich hatte das so verstanden, dass dies auch einfach eine Art ist, wie man (besseren) Code schreiben kann.

        Nein, MVC ist viel zu komplex, um mehr oder weniger einfache Anwendungsfälle zu verbessern.

        Die Minimalvariante wäre ein Controller, der den Request entgegennimmt. Er lässt die Geschäftlogik im Model erledigen, und gibt einer View die Daten, die daraus die Ausgabe erstellt.

        Dein Beispiel ist lediglich ein Anwendungsfall für einen Service.

        Das mag schon sein, mir ging es prinzipiell nur darum, diese 3 Teile richtig voneinander getrennt zu haben.

        Nein, weil es nichts damit zu tun hatte, wozu MVC sonst eingesetzt wird.

        dedlfix.

        1. Hallo dedlfix,

          man braucht schin die Größenordnung einer Anwendung, um ein auf MVC basierendes Framework sinnvoll einzusetzen.

          wie genau meinst Du das? Kannst Du das bitte näher erläutern?

          Nein, MVC ist viel zu komplex, um mehr oder weniger einfache Anwendungsfälle zu verbessern.

          Wie gesagt, mir ist es immer wieder auch für normalen PHP Code untergekommen. In diesem Video zum Beispiel wird auch vom MVC Model gesprochen, um OOP zu verstehen. Die sogenannten "Setters" und "Getters" bei OOP sind doch eigentlich nichts anderes als eine Trennung dieser 3 logischen Komponenten.

          Ich sagte ja, dass der gezeigte Fall nur als Beispiel dient. Aber etwa bei einem Login-System, das mit MySQL und PDO arbeitet, kann ich mir diese Programmier-Logik sehr wohl vorstellen.

          Mit lieben Grüßen

          Melvin Cowznofski

          --
          What – me worry?
          1. Hallo Melvin,

            ich habe mir das Video aus Zeitgründen jetzt nicht ganz angeschaut, nur im Minutenabstand durchgezappt.

            Aber ich würde sagen: Nein, das Video erklärt nicht OOP, sondern wie man eine PHP Seite basierend auf OOP und dem MVC Pattern baut.

            Rolf

            --
            sumpsi - posui - obstruxi
          2. Tach!

            man braucht schon die Größenordnung einer Anwendung, um ein auf MVC basierendes Framework sinnvoll einzusetzen.

            wie genau meinst Du das? Kannst Du das bitte näher erläutern?

            Du versuchst anscheinend nur deine OOP-Fähigkeiten zu verbessern. MVC ist aber nicht der Weg dafür, denn MVC ist ein Muster, um seine Anwendung im groben zu strukturieren, aber nicht die Details einer Klasse. Wie man Klassen besser gestaltet, kommt sehr auf den Anwendungsfall an, und dafür gibt es unzählige Lösungswege und auch Muster.

            Nein, MVC ist viel zu komplex, um mehr oder weniger einfache Anwendungsfälle zu verbessern.

            Wie gesagt, mir ist es immer wieder auch für normalen PHP Code untergekommen.

            Wenn du MVC in solch kleinen Dingen wie deinem Besipiel zu erkennen geglaubt hast, dann sieht es mir eher danach aus, als ob du MVC und dessen Anwendungsfälle nicht verstanden hast.

            In diesem Video zum Beispiel wird auch vom MVC Model gesprochen, um OOP zu verstehen. Die sogenannten "Setters" und "Getters" bei OOP sind doch eigentlich nichts anderes als eine Trennung dieser 3 logischen Komponenten.

            Getter und Setter haben nichts zu tun mit MVC. Der entscheidende Punkt in dem Video ist die Aussage ab Minute 1:30. Die zu lösende Aufgabe wird in die drei Teile Model, View und Controler in separaten Klassen zerlegt. Damit sich das lohnt, muss die Aufgabenstellung einigermaßen komplex sein.

            Ich sagte ja, dass der gezeigte Fall nur als Beispiel dient. Aber etwa bei einem Login-System, das mit MySQL und PDO arbeitet, kann ich mir diese Programmier-Logik sehr wohl vorstellen.

            Ja, da kann man das anwenden, aber dein Beispiel war viel zu simpel für MVC.

            dedlfix.

  3. Hallo Melvin,

    was du da zeigst, ist eine generelle Worker-Klasse für bestimmte String-Aufgaben.

    Bei MVC geht es aber nicht um Patterns zum Erledigen von Detailaufgaben, sondern um ein grundsätzliches Architekturpattern für Anwendungen. Web-Anwendungen sind ein Einsatzzweck.

    MVC - Model - View - Controller.

    Du hast ein Datenmodell, das die Daten repräsentiert, mit denen die Anwendung zu arbeiten hat. In einer Web-Anwendung sind das die Daten für einen Web Request.

    Du hast Views, die die Daten präsentieren. Was ein View ist, hängt von der verwendeten Plattform und Programmiersprache ab. Der View kümmert sich um die Präsentation. In PHP kann das ein Template sein. Das Template kann direkt auf das Modell zugreifen, oder man generiert vor der Übergabe an's Template erstmal eine Zwischenschicht, die die Präsentationsdaten aus dem Modell ableitet: Das View Model. Das Template kann auch in JavaScript laufen und die PHP Schicht generiert nur as View Model und schickt es als JSON-String zum Browser. Das MVC Pattern legt das nicht fest. Es verlangt nur, dass die Präsentation von der eigentlichen Datenverarbeitung getrennt wird.

    Du hast Controller, die die Verarbeitung steuern. Ein Controller kennt typischerweise eine oder mehrere Aktionen, und jede Benutzeraktion löst in einem Controller eine Aktion aus. Es ist üblich, dass ein Controller eine Klasse ist und eine Aktion eine Methode darin. Werden die Methoden zu groß, oder gibt es Teile die gemeinsam genutzt werden können, ist es durchaus zulässig, Subcontroller zu verwenden. Die eine Controller-Aktion, die durch die Benutzeraktion erzeugt wurde, orchestriert dann nur das Konzert der Subcontroller. Das Ergebnis einer Aktion ist immer ein View, der dem Anwender präsentiert wird - oder die Manipulation des aktiven Views (bei einer Single Page Application in Browser bzw. einer klassichen App).

    Du wirst Dinge in dieser Liste vermissen.

    • Wo ist die Fachlogik? MVC legt das nicht fest. Es gibt MVC-Frameworks, die es festlegen. Aber grundsätzlich kann sie im Modell stecken, sie kann im Controller stecken, oder man schiebt eine Business-Schicht zwischen Controller und Model.

    • Wie binde ich die Datenbank an? Das macht im einfachsten Fall der Controller. Besser ist es aber, ein fachliches Domänen-Modell zu konzipieren und für jede Fachdomäne ein sogenanntes Repository zu erzeugen. Das ist eine Klasse, in der alle Zugriffe für diese Fachdomäne programmiert werden. Z.B. ein UserRepository (für Login und Benutzereinstellungen), ein LobbyRepository (für die Daten der Lobby eines Spielservers), ein MessageRepository (für die Threads und Postings eines Forums). Ein Repository kümmert sich um das Caching von geladenen Objekten, um das Zurückschreiben geänderter Objekte in die DB, und enthält alle Zugriffe. Oft genug kann man statt des Repository auch eine ORM (object-relation mapping) Library nutzen.

    • Wie bekomme ich die Daten eines Web-Requests in Objekte und wie plausibilisiere ich sie? Um Teil 1 kümmert sich ein MVC Framework. Hast Du keins, muss es der Controller machen. Teil 2 kann teilweise vom Framework gemacht werden, oder der Controller. Auch hier gilt: Subcontroller erleichtern die Arbeit. Ein Subcontroller kann einen Request parsen, plausibilisieren und dann Modellobjekte liefern. Oder einen Error View. Oder ein Flag, das den Hauptcontroller zum Generieren des Error View bewegt.

    • Woher weiß ich, welcher Controller und welche Aktion auf Grund eines Webrequests auszuführen sind? Das macht das MVC Framework. In einer Web-Anwendung nach MVC definierst Du ein Requestrouting. Das sind Patterns, gegen die die URL gematcht wird. Ein Beispiel wäre www.example.org/users/edit/4711. Diese URL spricht den User-Controller an und die Edit-Aktion. 4711 ist die Objekt-ID, auf die sich der Request bezieht. Sowas kann man im Apache mit mod_rewrite auf myapp.php?ctrl=users&action=edit&id=4711 mappen, oder man sagt dem Apache, dass er bei solchen URLs nicht nur nach einem Ordner users, sondern auch nach einer users.php suchen soll, und die startet dann den Router an. Andere Webserver (z.B. der IIS unter Windows) gestatten Dir auch das Schreiben sogenannter HTTP Handler, die aktiv werden bevor der Server nach einer statischen Ressource sucht. Der HTTP Handler bekommt dann einfach die URL und kann draus machen was er will. ASP.NET MVC macht das zum Beispiel.

    Rolf

    --
    sumpsi - posui - obstruxi
    1. Hallo Rolf,

      vielen Dank für Deine ausführliche Antwort! Mein technisches Verständnis reicht leider nicht aus, um das auch nur ansatzweise nachzuvollziehen. Ich werde mir trotzdem die Zeit nehmen, Deine Erklärungen mit Hilfe von GOOGLE hoffentlich besser zu verstehen.

      Ich resümiere einfach daraus, dass der von mir gezeigte Beispielcode nichts mit MVC zu tun hat und das, was ich gemacht habe, einfach nur angewandtes OOP ist.

      Mit lieben Grüßen

      Melvin Cowznofski

      --
      What – me worry?
  4. Hallo Melvin

    Ich würde jetzt gerne wissen, ob das (abgesehen von der Unsinnigkeit der Aufgabe) ein korrektes Umsetzen des MCV Modells mit OOP ist, damit ich weiß, ob ich die Sache jetzt halbwegs richtig verstanden habe.

    Entwurfsmuster wie das MVC skizzieren Lösungen für bestimmte Problemklassen. Wenn ein Problem nicht zu der Klasse an Problemen gehört, die das Entwurfsmuster zu lösen gedenkt, dann lässt es sich auch nicht damit lösen. Dein Beispiel kränkelt daran, dass es nicht die Charaktereigenschaften hat, die man für MVC voraussetzt.

    Unser Wiki beinhaltet ein Tutorial, das erklärt am Beispiel einer To-do-Liste, wie das MVC-Muster funktioniert. Vielleicht hilft dir das ja beim Verständnis.

    Viele Grüße

    1. Hallo 1unitedpower,

      oh. Da hätte ich mir ja viel Tipperei sparen können - das das Tutorial hatte ich gar nicht mehr gedacht.

      Rolf

      --
      sumpsi - posui - obstruxi