An Introduction to the Front Controller Pattern, Part 2
Core points
- The front-end controller acts as a centralized proxy for the application, assigning commands to predefined handlers, such as page controllers or REST resources.
- The front-end controller can maintain a compact structure, route and dispatch incoming requests, and can also be extended to a fully functional RESTful controller, parse HTTP verbs, adapt to pre/post dispatch hooks, etc.
- This article demonstrates how to deploy a small but scalable HTTP framework that works with front-end controllers, standalone routers, and schedulers while handling request/response cycles independently.
- The author also introduced the process of building a front-end controller from scratch, including defining classes to simulate data and behaviors of typical HTTP request/response cycles, building routing modules, and setting up schedulers.
- Front-end controller mode has the advantages of centralized control, reducing code duplication, and improving modularity and separation of concerns, but it may not be suitable for all web applications and may result in single point of failure if implemented improperly.
The front-end controller is like a centralized proxy in an application, and its main area of focus is to statically or dynamically assign commands to predefined handlers such as page controllers, REST resources, or anything else that comes to mind. Building at least one simple front-end controller is a very useful experience to understand its details, and to promote this idea from a pragmatic point of view, I introduced in an introductory post the implementation of a artificial front-end controller that will route and all the logic required to dispatch requests is packaged within the boundaries of a class. One of the best aspects of front-end controllers is that you can keep them as compact structures, route and dispatch incoming requests only, or you can show your creativity and implement a fully functional RESTful controller capable of parsing HTTP Verbs, adaptation pre/post dispatch hooks, etc., all behind a unified API. However, while this approach is attractive, it violates the single responsibility principle (SRP) and the nature of OOP itself proactively delegating different tasks to multiple fine-grained objects. So, does this mean I am just another sinful soul who dares to break the SRP precepts? In a sense, yes. So I want to eliminate my sin by showing you how to easily deploy a small but scalable HTTP framework that is able to work with front-end controllers with standalone routers and schedulers. In addition, the entire request/response cycle will be handled independently by several reusable classes that can naturally be adjusted at will. Given that there are a large number of fully-featured components-packaged HTTP frameworks available, it seems ridiculous to implement a front-end controller that routes and dispatches requests from scratch even though these classes retain the nature of SRP. To avoid being judged for reinventing the wheel, some parts of my custom implementation will be inspired by the clever EPHPMVC library written by Lars Strojny.
Analyze request/routing/scheduling/response cycle
The task we should solve first is to define several classes responsible for simulating data and behavior of typical HTTP request/response cycles. This is the first class, and the interface it implements:
<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>
The Request class encapsulates the incoming URI and parameter array and simulates an extremely simple HTTP request. For brevity, additional data members such as the method set associated with the relevant request have been intentionally excluded. If you want to add them to the class, continue. Having a thin HTTP request wrapper that exists independently is good, but it will end up being useless without coupling with the corresponding parts of the data and behavior that simulates a typical HTTP response. Let's fix and build this supplemental component:
<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>
The Response class is undoubtedly more active than its partner Request. It acts as a base container that allows you to stack HTTP headers at will and is able to send them to the client. Since these classes perform their operations independently, it's time to start building the next part of the front-end controller. In a typical implementation, the routing/dispatch process is mostly encapsulated in the same approach, which is frankly not too bad at all. However, in this case, it is better to break down these processes and delegate them to different classes. In this way, things will be more balanced in terms of equal responsibility. Here are the batches of classes that make the routing module run:
<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>
As one might expect, there are many options when implementing functional routing mechanisms. At least in my opinion, the above method is both practical and direct. It defines a separate Route class that binds the path to a given operation controller, and a simple router whose responsibilities are limited to checking whether the stored route matches the URI associated with a specific request object. To finally solve the problem, we need to set up a quick scheduler that can be used side by side with the previous class. This is how the following class does:
<code>class Dispatcher { public function dispatch($route, $request, $response) $controller = $route->createController(); $controller->execute($request, $response); } }</code>
Scan the Dispatcher and you will notice two things. First, it does not carry any state. Second, it implicitly assumes that each operation controller will run under the surface of the execute() method. This can be refactored to a slightly more flexible pattern if you want (the first thing that comes to mind is to tweak the implementation of the Route class), but for simplicity, I'll keep the scheduler unchanged. So far, you might be wondering how to place a front-end controller that is able to combine all previous classes together. Don't worry, next is!
(Due to space limitations, subsequent content will be truncated. Please provide the rest of the content and I will continue to complete the pseudo-original.)
The above is the detailed content of An Introduction to the Front Controller Pattern, Part 2. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics











PHP and Python each have their own advantages, and choose according to project requirements. 1.PHP is suitable for web development, especially for rapid development and maintenance of websites. 2. Python is suitable for data science, machine learning and artificial intelligence, with concise syntax and suitable for beginners.

In PHP, password_hash and password_verify functions should be used to implement secure password hashing, and MD5 or SHA1 should not be used. 1) password_hash generates a hash containing salt values to enhance security. 2) Password_verify verify password and ensure security by comparing hash values. 3) MD5 and SHA1 are vulnerable and lack salt values, and are not suitable for modern password security.

PHP is widely used in e-commerce, content management systems and API development. 1) E-commerce: used for shopping cart function and payment processing. 2) Content management system: used for dynamic content generation and user management. 3) API development: used for RESTful API development and API security. Through performance optimization and best practices, the efficiency and maintainability of PHP applications are improved.

PHP is a scripting language widely used on the server side, especially suitable for web development. 1.PHP can embed HTML, process HTTP requests and responses, and supports a variety of databases. 2.PHP is used to generate dynamic web content, process form data, access databases, etc., with strong community support and open source resources. 3. PHP is an interpreted language, and the execution process includes lexical analysis, grammatical analysis, compilation and execution. 4.PHP can be combined with MySQL for advanced applications such as user registration systems. 5. When debugging PHP, you can use functions such as error_reporting() and var_dump(). 6. Optimize PHP code to use caching mechanisms, optimize database queries and use built-in functions. 7

PHP type prompts to improve code quality and readability. 1) Scalar type tips: Since PHP7.0, basic data types are allowed to be specified in function parameters, such as int, float, etc. 2) Return type prompt: Ensure the consistency of the function return value type. 3) Union type prompt: Since PHP8.0, multiple types are allowed to be specified in function parameters or return values. 4) Nullable type prompt: Allows to include null values and handle functions that may return null values.

PHP is still dynamic and still occupies an important position in the field of modern programming. 1) PHP's simplicity and powerful community support make it widely used in web development; 2) Its flexibility and stability make it outstanding in handling web forms, database operations and file processing; 3) PHP is constantly evolving and optimizing, suitable for beginners and experienced developers.

PHP and Python each have their own advantages, and the choice should be based on project requirements. 1.PHP is suitable for web development, with simple syntax and high execution efficiency. 2. Python is suitable for data science and machine learning, with concise syntax and rich libraries.

PHP and Python have their own advantages and disadvantages, and the choice depends on project needs and personal preferences. 1.PHP is suitable for rapid development and maintenance of large-scale web applications. 2. Python dominates the field of data science and machine learning.
