Creating a Simple PHP MVC Framework from Scratch
MVC stands for Model-View-Controller, and it is a design pattern commonly used in software development, especially in web application development. As mentioned in the name, the application is separated into three interconnected components to promote modularity, maintainability, and ease of development.
Model (M) represents the application’s data and business logic. Which means it’s responsible for retrieving, manipulating, and storing data.
View (V) acts as the presentation layer, which is responsible for presenting the data to the end user.
Controller (C) is an intermediary between the Model and the View. It receives user input and determines which Model or Models to invoke and which View to present.
Based on these clarifications, the MVC pattern enforces a clear separation of concerns between data management — Model, user interface — View, and application logic — Controller. This separation makes it easier to understand, maintain and extend an application.
Prerequisites
In this tutorial, you will learn how to build a simple PHP MVC Framework from scratch. To follow along, you should have a basic understanding of the following:
- PHP OOP concepts
- Composer — the PHP package manager
- HTML/CSS — not required for the framework, but to build the pages after
Setting up the Project
Create a new directory for your project and open it in your favorite editor. Then, in the terminal, run composer init
to initialize a new Composer project.
composer init
You can press enter, leaving all the questions empty except for the dev dependencies. When you are asked to add the dependencies and dev dependencies, type “no” and press enter for now.
Once completed, you will see a message like this:
“PSR-4 autoloading configured. Use “namespace Maheshsamudra\SimplePhpMvcStarter;” in src/”
For simplicity, we’ll change the namespace to something shorter, such as App. To do that, change the key of the “psr-4” in composer.json
file:
"Maheshsamudra\\SimplePhpMvcStarter\\" -> "App\\"
Then, run composer dump-autoload
to which will update the classes that must be included in the project.
Directory Structure
public/ # this is where the domain is pointed
src/
Controllers/
Models/
Routes/
Views/
vendor/ # automatically created by composer
Building the Core Components
Setting up the public folder
Create a new file called index.php in the public/
folder. This file will serve as the entry point of the application.
<?php
require '../vendor/autoload.php';
$router = require '../src/Routes/index.php';
Handling the Routes
Create a Router.php
file inside src/
folder. This will map the routes to the correct controller.
<?php
namespace App;
class Router
{
protected $routes = [];
private function addRoute($route, $controller, $action, $method)
{
$this->routes[$method][$route] = ['controller' => $controller, 'action' => $action];
}
public function get($route, $controller, $action)
{
$this->addRoute($route, $controller, $action, "GET");
}
public function post($route, $controller, $action)
{
$this->addRoute($route, $controller, $action, "POST");
}
public function dispatch()
{
$uri = strtok($_SERVER['REQUEST_URI'], '?');
$method = $_SERVER['REQUEST_METHOD'];
if (array_key_exists($uri, $this->routes[$method])) {
$controller = $this->routes[$method][$uri]['controller'];
$action = $this->routes[$method][$uri]['action'];
$controller = new $controller();
$controller->$action();
} else {
throw new \Exception("No route found for URI: $uri");
}
}
}
Now, to set the initial route, create aindex.php
file inside src/Routes/
folder. You can map the routes for POST and GET requests here separately.
<?php
use App\Controllers\HomeController;
use App\Router;
$router = new Router();
$router->get('/', HomeController::class, 'index');
$router->dispatch();
Controllers — Handling the home page
First, create a Controller.php
inside the src/
folder.
<?php
namespace App;
class Controller
{
protected function render($view, $data = [])
{
extract($data);
include "Views/$view.php";
}
}
Now, we need to add a HomeController
to handle the request. Inside thesrc/Controllers/
folder, create HomeController.php
with an index
method to handle the home page.
<?php
namespace App\Controllers;
use App\Controller;
class HomeController extends Controller
{
public function index()
{
$this->render('index');
}
}
Adding the Views
Finally, to serve the home page, create index.php
file inside thesrc/Views/
folder.
<h1>Welcome to Simple PHP MVC Starter!</h1>
Testing the progress
Now, the app is ready to serve the home page. Navigate to the public folder and run the built-in PHP web server to test it.
cd simple-php-mvc-starter/public
php -S localhost:9999
If everything works, you should see this in the browser:
Creating a Model
Create a new file Journal.php
inside the Models/
directory. This represents the Journals in the application.
<?php
namespace App\Models;
class Journal
{
public $name;
public $publishedYear;
public function __construct($name, $publishedYear)
{
$this->name = $name;
$this->publishedYear = $publishedYear;
}
}
Now, let’s add some Journals to the Home page. Update the HomeController.php
to load come Journals.
<?php
namespace App\Controllers;
use App\Controller;
use App\Models\Journal;
class HomeController extends Controller
{
public function index()
{
$journals = [
new Journal('My Third Journal Entry', '2023'),
new Journal('My Second Journal Entry', '2022'),
new Journal('My First Journal Entry', '2021')
];
$this->render('index', ['journals' => $journals]);
}
}
Finally, update the index.php
inside the Views/
folder.
<h1>Welcome to Simple PHP MVC Starter!</h1>
<ul>
<?php foreach ($journals as $journal) : ?>
<li><?= $journal->name ?> (<?= $journal->publishedYear ?>)</li>
<?php endforeach; ?>
</ul>
That’s it. You have successfully built your first PHP MVC framework from scratch.
Eventhough this is a simple start, creating a PHP MVC framework from scratch is a significant undertaking, and it’s a big project that can take a considerable amount of time and effort. Having that exposure is an excellent addition to your resume.
The example code is available on GitHub. Thanks for reading & happy coding!