Understanding PHP Router Scripts

On the same Video link that I posted in my other topic there is a Project where such class is written:

class Bootstrap{
	private $controller;
	private $action;
	private $request;

	public function __construct($request){
		$this->request = $request;
		if($this->request['controller'] == ""){
			$this->controller = 'home';
		} else {
			$this->controller = $this->request['controller'];
		}
		if($this->request['action'] == ""){
			$this->action = 'index';
		} else {
			$this->action = $this->request['action'];
		}
	}

	public function createController(){
		// Check Class
		if(class_exists($this->controller)){
			$parents = class_parents($this->controller);
			// Check Extend
			if(in_array("Controller", $parents)){
				if(method_exists($this->controller, $this->action)){
					return new $this->controller($this->action, $this->request);
				} else {
					// Method Does Not Exist
					echo '<h1>Method does not exist</h1>';
					return;
				}
			} else {
				// Base Controller Does Not Exist
				echo '<h1>Base controller not found</h1>';
				return;
			}
		} else {
			// Controller Class Does Not Exist
			echo '<h1>Controller class does not exist</h1>';
			return;
		}
	}
}

In this the construct function:

	public function __construct($request){
		$this->request = $request;
		if($this->request['controller'] == ""){
			$this->controller = 'home';
		} else {
			$this->controller = $this->request['controller'];
		}
		if($this->request['action'] == ""){
			$this->action = 'index';
		} else {
			$this->action = $this->request['action'];
		}
	}

I have huge difficulty in understanding this part →

$this->request['controller']

Is this something, which is natively defined in PHP? → request['controller']

Additionally, In this contsruct fucntion are we conditionally trying to call some template system?
Such as: admin template, user action template etc?

Nah. I have not looked at your link but I suspect there is an index.php file which either creates a request object or array using PHP superglobals such as $_SERVER. It probably does some routing stuff as well to link a given request url to a controller action.

What you posted is really bad code. Unless it is a homework assignment or something then I’d suggest using a real framework such as Symfony. You need a few additional steps to get started but you will avoid getting led down some pretty dark paths.

3 Likes

Currently, this is at index.php →

<?php
// Include Config
require('config.php');

require('classes/Bootstrap.php');

$bootstrap = new Bootstrap($_GET);
$controller = $bootstrap->createController();

I am a newbie so yes a kind of Homework assignment sir.

Would it be possible to add some more insight into it?

So $_GET is one of those super global arrays which contain your url query parameters from the browser. Presumably the video tells you to open a browser browse to something like:

index.php?controller=DefaultController&action=index

The bootstrap class then creates a controller of the specified class name and calls the action method. It can work but it’s quite fragile to say the least.

2 Likes

Didn’t fully understand, but got some clue.

This might help. Or it could cause your head to spin around and explode. But at least it has some pretty pictures.

1 Like

It indeed seems helpful. I will write back to you regarding my learning. Thanks for the help and guidance.

even the Wordpress follow such structure →

Router.php →

<?php 
class Router{
	protected $routes = [];
	protected $params = [];
	public function add($route, $params){
		$this->routes[$route] = $params;
	}	
	public function getRoutes(){
		return $this->routes; 
	}
	public function match($url){
		foreach ($this->routes as $route => $params) {
			if ($url==$route) {
				$this->params = $params;
				return true; 
			}
		}
		return false;
	}
	public function getParams(){
		return $this->params; 
	}
}

index.php →

<?php 
declare(strict_types=1);
error_reporting(E_ALL);
ini_set('display_errors', 'true');

// Front Controller
// echo 'Reqested URL = "'.$_SERVER['QUERY_STRING'].'"';

// Routing
require '../core/Router.php';
$router = new Router();
echo get_class($router);


// Add the Routes
$router->add('',['controller'=>'Home','action'=>'index']);
$router->add('posts',['controller'=>'Posts','action'=>'index']);
$router->add('posts/new',['controller'=>'Posts','action'=>'new']);

// Displaying the Routing Table
// echo "<pre>";
// var_dump($router->getRoutes());
// echo "</pre>";



// Match the requested route
$url = $_SERVER['QUERY_STRING'];

if ($router->match($url)) {
    echo '<pre>';
    var_dump($router->getParams());
    echo '</pre>';
} else {
    echo "No route found for URL '$url'";
}

This is how we are generating the associative array →

// Add the Routes
$router->add('',['controller'=>'Home','action'=>'index']);
$router->add('posts',['controller'=>'Posts','action'=>'index']);
$router->add('posts/new',['controller'=>'Posts','action'=>'new']);

I have difficulty understanding this part →

public function match($url){
		foreach ($this->routes as $route => $params) {
			if ($url==$route) {
				$this->params = $params;
				return true; 
			}
		}
		return false;
	}

This should only put value in new array params→ $this->params = $params;, but is putting the whole associative array part of that route URL?
How come when $params are just a value?

Live can be checked here.

Where is this router coming from all of a sudden?

Like @ahundiak said, it would be better to start out with a full framework that actually has decent implementations of these kind of concepts, rather one that is based on arrays that are supposed to have the correct keys. It’s asking for trouble.

Hi there, Suddenly moving to Symfony is not easy for me sir. Although I read a lot of documentation shared by the @ahundiak

The basics of PHP are not yet in full control. I stumbled upon this course on udemy

The course is very concise and to the point. I am half done.

Please don’t see this as if you are advising and helping and I am ignoring. I will focus on that as well. I also believe that alignment will automatically occur as soon as I get some Knack for PHP.
while doing this course I am also able to learn some other things.

I was committing the mistake in regex, which I fixed later:

// $reg_exp = "/^(?P<controller>[a-z-]+)\/(?P<action>[a-z-]+)$/";
    $reg_exp = "/^\/(?P<controller>[a-z-]+)\/(?P<action>[a-z-]+)\/$/";

All small learnings are building blocks for me.

The trap you seem to be falling into, and that a lot of developers fall into, is that you’re putting a lot of time and effort into boring plumbing code. In essence, routers are totally boring, they take a URL as input and then return some sort of controller that needs to be executed based on that URL. There are subtle differences between different routers, but in essence that is all they do.

When you know the concept of a router and know how to apply one in your project, what’s happening under the hood is completely irrelevant. Just like you don’t need to know exactly how an engine works in order to drive a car.

The real meat of software is actually implementing business logic, the part of your code that is unique to your problem, that cannot be solved by dropping in some standard component (such as a router).

Routers are a solved problem, pick one, use it, and forget it. There is no honor to be had by rolling your own. In fact it can even be detrimental, because you need to invest time writing it, maintaining it, making sure it’s secure, etc, etc. All of which you don’t have to do for an off-the-shelf router (such as the one from Symfony), saving you time you can then use to solve your actual problem.

2 Likes

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.