
PHP Advanced Concepts: Implementing a Custom PHP Router
Understanding the Basics of Routing
Routing is the mechanism that maps incoming requests to specific code that handles those requests. A well-structured router allows developers to define routes in a clean and organized manner, making it easier to manage application logic.
Key Features of Our Custom Router
- Dynamic Routing: Support for dynamic URL segments.
- HTTP Method Support: Differentiate between GET, POST, PUT, DELETE, etc.
- Middleware Integration: Ability to add middleware for request handling.
- Error Handling: Graceful handling of 404 errors.
Building the Router Class
Let's start by creating a basic Router class that will handle our routing logic.
<?php
class Router {
private $routes = [];
public function addRoute($method, $path, $callback) {
$this->routes[] = [
'method' => $method,
'path' => $path,
'callback' => $callback,
];
}
public function dispatch($method, $uri) {
foreach ($this->routes as $route) {
if ($route['method'] === $method && $route['path'] === $uri) {
return call_user_func($route['callback']);
}
}
http_response_code(404);
echo "404 Not Found";
}
}Adding Routes
Now that we have a basic router class, we can add routes to our application. Here's how to define routes using the addRoute method.
$router = new Router();
$router->addRoute('GET', '/home', function() {
return "Welcome to the Home Page!";
});
$router->addRoute('GET', '/about', function() {
return "This is the About Page.";
});
$router->addRoute('POST', '/submit', function() {
return "Form submitted!";
});Dynamic Routing
To handle dynamic segments in URLs, we can modify our dispatch method to use regular expressions. This allows us to capture dynamic parameters from the URL.
public function dispatch($method, $uri) {
foreach ($this->routes as $route) {
$pattern = preg_replace('/\{(\w+)\}/', '([^/]+)', $route['path']);
if ($route['method'] === $method && preg_match("#^$pattern$#", $uri, $matches)) {
array_shift($matches); // Remove the full match
return call_user_func_array($route['callback'], $matches);
}
}
http_response_code(404);
echo "404 Not Found";
}Example of Dynamic Routes
Now, let's add a dynamic route to our router.
$router->addRoute('GET', '/user/{id}', function($id) {
return "User ID: " . htmlspecialchars($id);
});
// Dispatching a request
$router->dispatch('GET', '/user/123'); // Output: User ID: 123Middleware Integration
Middleware can be used to perform actions before or after route handling. Here’s a simple implementation of middleware support in our router.
private $middleware = [];
public function addMiddleware(callable $middleware) {
$this->middleware[] = $middleware;
}
public function dispatch($method, $uri) {
foreach ($this->middleware as $middleware) {
call_user_func($middleware);
}
// Existing dispatch logic...
}Example Middleware
You can create middleware for logging or authentication. Here’s an example of a simple logging middleware.
$router->addMiddleware(function() {
error_log("Request made at: " . date('Y-m-d H:i:s'));
});Error Handling
In our router, we have already implemented basic error handling for 404 errors. However, you can extend this to include custom error pages or logging.
public function dispatch($method, $uri) {
// Existing logic...
http_response_code(404);
include '404.php'; // Custom 404 page
}Conclusion
In this tutorial, we have built a custom PHP router that supports dynamic routing, HTTP methods, middleware, and error handling. This router can serve as a foundation for more complex applications, providing a clear structure for managing routes.
