Php Mvc Project With Routing (complete Example)

I’ve created a complete working MVC project with routing for you in the canvas.

This is not just theory — you can copy this and run it directly.

🚀 How to run it

  1. Create the folder structure exactly as shown
  2. Put files in correct folders
  3. Enable Apache mod_rewrite
  4. Open in browser:
    • http://localhost/ → Home page
    • http://localhost/Home/users → Users page

🔥 What this project includes

  • Clean MVC structure
  • Custom Router (no framework)
  • Dynamic URL handling
  • Controller → Model → View flow
  • Reusable base controller
<?php
// ===============================
// PROJECT STRUCTURE
// ===============================
/*
/project
│
├── /app
│   ├── /controllers
│   │     └── HomeController.php
│   │
│   ├── /models
│   │     └── UserModel.php
│   │
│   └── /views
│         ├── home.php
│         └── users.php
│
├── /core
│   ├── Router.php
│   └── Controller.php
│
├── /public
│   └── index.php
│
└── .htaccess
*/

// ===============================
// .htaccess (URL Routing)
// ===============================
/*
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.+)$ public/index.php?url=$1 [QSA,L]
*/

// ===============================
// public/index.php (Entry Point)
// ===============================

require_once '../core/Router.php';

$url = $_GET['url'] ?? '';

$router = new Router();
$router->dispatch($url);


// ===============================
// core/Router.php
// ===============================

class Router {
    public function dispatch($url) {
        $url = trim($url, '/');
        $parts = explode('/', $url);

        $controllerName = !empty($parts[0]) ? ucfirst($parts[0]) . 'Controller' : 'HomeController';
        $method = $parts[1] ?? 'index';

        $controllerFile = "../app/controllers/$controllerName.php";

        if (!file_exists($controllerFile)) {
            die('Controller not found');
        }

        require_once $controllerFile;

        $controller = new $controllerName();

        if (!method_exists($controller, $method)) {
            die('Method not found');
        }

        $controller->$method();
    }
}


// ===============================
// core/Controller.php (Base Controller)
// ===============================

class Controller {
    public function view($view, $data = []) {
        extract($data);
        require "../app/views/$view.php";
    }
}


// ===============================
// app/controllers/HomeController.php
// ===============================

require_once '../core/Controller.php';
require_once '../app/models/UserModel.php';

class HomeController extends Controller {

    public function index() {
        $this->view('home', ['title' => 'Welcome MVC']);
    }

    public function users() {
        $model = new UserModel();
        $users = $model->getUsers();

        $this->view('users', ['users' => $users]);
    }
}


// ===============================
// app/models/UserModel.php
// ===============================

class UserModel {
    public function getUsers() {
        return [
            ['name' => 'Aditya'],
            ['name' => 'Rahul'],
            ['name' => 'Priya']
        ];
    }
}


// ===============================
// app/views/home.php
// ===============================
?>
<!DOCTYPE html>
<html>
<head>
    <title><?= $title ?></title>
</head>
<body>
    <h1><?= $title ?></h1>
    <a href="/Home/users">View Users</a>
</body>
</html>

<?php
// ===============================
// app/views/users.php
// ===============================
?>
<!DOCTYPE html>
<html>
<head>
    <title>Users</title>
</head>
<body>
    <h2>User List</h2>
    <ul>
        <?php foreach($users as $user): ?>
            <li><?= $user['name'] ?></li>
        <?php endforeach; ?>
    </ul>

    <a href="/">Back Home</a>
</body>
</html>