Heim >Backend-Entwicklung >PHP-Tutorial >Eine Einführung in das Front -Controller -Muster, Teil 2
Kernpunkte
Der Front-End-Controller ist wie ein zentraler Proxy in einer Anwendung, und sein Hauptfokusbereich besteht darin, vordefinierten Handlern wie Seitencontroller, REST-Ressourcen oder irgendetwas anderes Befehle zuzuweisen, das in den Sinn kommt . Das Aufbau von mindestens einem einfachen Front-End-Controller ist eine sehr nützliche Erfahrung, um ihre Details zu verstehen und diese Idee aus pragmatischer Sicht zu fördern, habe ich in einem einführenden Post die Implementierung eines künstlichen Front-End-Controllers eingeführt, der Routing und Route und wird Alle für das Versand von Anfragen erforderlichen Logik sind innerhalb der Grenzen einer Klasse verpackt. Einer der besten Aspekte von Front-End-Controllern ist, dass Sie sie nur als kompakte Strukturen, Routen- und Versandanträge aufbewahren können oder Ihre Kreativität zeigen und einen voll funktionsfähigen Rastful-Controller implementieren können, der HTTP-Verben analysieren kann, Anpassung vor/Post Entsenden Sie Hooks usw., alles hinter einer einheitlichen API. Obwohl dieser Ansatz attraktiv ist, verstößt er gegen das Prinzip der einzelnen Verantwortung (SRP) und die Art der OOP selbst, die verschiedene Aufgaben proaktiv an mehrere feinkörnige Objekte delegiert. Bedeutet das also, dass ich nur eine andere sündige Seele bin, die es wagt, die SRP -Vorschriften zu brechen? In gewisser Weise ja. Daher möchte ich meine Sünde beseitigen, indem ich Ihnen zeige, wie Sie ein kleines, aber skalierbares HTTP-Framework problemlos bereitstellen können, das mit Front-End-Controllern mit eigenständigen Routern und Schedulern arbeiten kann. Darüber hinaus wird der gesamte Antrags-/Antwortzyklus unabhängig von mehreren wiederverwendbaren Klassen behandelt, die natürlich nach Belieben eingestellt werden können. Angesichts der Tatsache, dass es eine große Anzahl von mit voll befriedigten Komponenten gepackten HTTP-Frameworks gibt, erscheint es lächerlich, einen Front-End-Controller zu implementieren, der Anfragen von Grund auf neu stellt und entsendet, obwohl diese Klassen die Art von SRP behalten. Um zu vermeiden, dass das Rad neu erfunden wird, werden einige Teile meiner benutzerdefinierten Implementierung von der von Lars Strojny geschriebenen Clever EphpMVC -Bibliothek inspiriert.
Analysieren Sie die Anforderung/Routing/Planung/Antwortzyklus
Die Aufgabe, die wir zuerst lösen sollten, besteht darin, mehrere Klassen zu definieren, die für die Simulation von Daten und das Verhalten typischer HTTP -Anforderungs-/Antwortzyklen verantwortlich sind. Dies ist die erste Klasse und die Schnittstelle, die sie implementiert:
<code>class Request { public function __construct($uri, $params) { $this->uri = $uri; $this->params = $params; } public function getUri() { return $this->uri; } public function setParam($key, $value) { $this->params[$key] = $value; return $this; } public function getParam($key) { if (!isset($this->params[$key])) { throw new \InvalidArgumentException("The request parameter with key '$key' is invalid."); } return $this->params[$key]; } public function getParams() { return $this->params; } }</code>Die
Die Anforderungsklasse verkaps das eingehende URI- und Parameter -Array und simuliert eine extrem einfache HTTP -Anforderung. Für die Kürze wurden zusätzliche Datenelemente wie die mit der entsprechende Anfrage verbundene Methode absichtlich ausgeschlossen. Wenn Sie sie der Klasse hinzufügen möchten, fahren Sie fort. Es ist gut, eine dünne HTTP -Anforderungsverpackung zu haben, die unabhängig existiert, aber es wird nutzlos, ohne sich mit den entsprechenden Teilen der Daten und des Verhaltens zu koppeln, die eine typische HTTP -Antwort simuliert. Lassen Sie uns diese ergänzende Komponente beheben und erstellen:
<code>class Response { public function __construct($version) { $this->version = $version; } public function getVersion() { return $this->version; } public function addHeader($header) { $this->headers[] = $header; return $this; } public function addHeaders(array $headers) { foreach ($headers as $header) { $this->addHeader($header); } return $this; } public function getHeaders() { return $this->headers; } public function send() { if (!headers_sent()) { foreach($this->headers as $header) { header("$this->version $header", true); } } } }</code>
Die Antwortklasse ist zweifellos aktiver als ihre Partneranfrage. Es fungiert als Basisbehälter, mit dem Sie HTTP -Header nach Belieben stapeln können, und kann sie an den Kunden senden. Da diese Klassen ihre Operationen unabhängig ausführen, ist es an der Zeit, den nächsten Teil des Front-End-Controllers aufzubauen. In einer typischen Implementierung wird der Routing-/Versandprozess meist im selben Ansatz eingekapselt, was ehrlich gesagt überhaupt nicht schlecht ist. In diesem Fall ist es jedoch besser, diese Prozesse aufzubrechen und an verschiedene Klassen zu delegieren. Auf diese Weise werden die Dinge in Bezug auf die gleiche Verantwortung ausgeglichener. Hier sind die Stapel von Klassen, die das Routing -Modul ausführen:
<code>class Route { public function __construct($path, $controllerClass) { $this->path = $path; $this->controllerClass = $controllerClass; } public function match(RequestInterface $request) { return $this->path === $request->getUri(); } public function createController() { return new $this->controllerClass; } } class Router { public function __construct($routes) { $this->addRoutes($routes); } public function addRoute(RouteInterface $route) { $this->routes[] = $route; return $this; } public function addRoutes(array $routes) { foreach ($routes as $route) { $this->addRoute($route); } return $this; } public function getRoutes() { return $this->routes; } public function route(RequestInterface $request, ResponseInterface $response) { foreach ($this->routes as $route) { if ($route->match($request)) { return $route; } } $response->addHeader("404 Page Not Found")->send(); throw new \OutOfRangeException("No route matched the given URI."); } }</code>
Wie man vielleicht erwartet, gibt es bei der Implementierung funktionaler Routing -Mechanismen viele Optionen. Zumindest meiner Meinung nach ist die obige Methode sowohl praktisch als auch direkt. Es definiert eine separate Routenklasse, die den Pfad an einen bestimmten Betriebscontroller bindet, und einen einfachen Router, dessen Verantwortung darauf beschränkt ist, zu überprüfen, ob die gespeicherte Route mit dem URI übereinstimmt, das einem bestimmten Anforderungsobjekt zugeordnet ist. Um das Problem endlich zu lösen, müssen wir einen schnellen Scheduler einrichten, der neben der vorherigen Klasse nebeneinander verwendet werden kann. So macht die folgende Klasse:
<code>class Dispatcher { public function dispatch($route, $request, $response) $controller = $route->createController(); $controller->execute($request, $response); } }</code>
Scannen Sie den Dispatcher und Sie werden zwei Dinge bemerken. Erstens trägt es keinen Zustand. Zweitens wird implizit davon ausgegangen, dass jeder Betriebscontroller unter der Oberfläche der Execute () -Methode ausgeführt wird. Dies kann auf ein etwas flexibleres Muster neu ausgerichtet werden, wenn Sie möchten (das erste, was Ihnen in den Sinn kommt, ist, die Implementierung der Routenklasse zu optimieren), aber der Einfachheit halber werde ich den Scheduler unverändert halten. Bisher fragen Sie sich vielleicht, wie Sie einen Front-End-Controller platzieren können, der alle früheren Klassen miteinander kombinieren kann. Mach dir keine Sorgen, als nächstes ist es!
(aufgrund von Platzbeschränkungen wird der nachfolgende Inhalt abgeschnitten. Bitte geben Sie den Rest des Inhalts an und ich werde den Pseudooriginal weiter vervollständigen.)
Das obige ist der detaillierte Inhalt vonEine Einführung in das Front -Controller -Muster, Teil 2. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!