Create Your Own lightweight PHP MVC Framework
Using the MVC design pattern is a great way to simplify PHP app development. Using a framework written by someone else is usually the best option; the Zend Framework for example. It is, however, at least a good exercise to write your own MVC framework to gain a better understanding of how the roles of the MVC interact. It may also be appropriated to use such a light implementation of the MVC as we are about to roll together for certain site’s development.
Folder structure
First thing first, setup a basic file structure to hold the various elements of our simple framework.

Bootstrapping
Next create an index.php file. You of course have to have this file display ‘hello world’. Now what must happen is all requests made to your site must be internally directed to this file. This is done using apache’s rewrite module; it allows your browser to display the URL the user requested while internally handling a different URL, among other things. So create your .htaccess file and add the following code. This code sends all requests to index.php with a GET variable named request storing the URL the user requested. Make sure this works, when requesting any URL within the site, below the .htaccess file, you should see ‘hello world’ rather than a 404 error.
.htaccess
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?request=$1 [L,QSA]
Now the bootstrapping itself is responsible for requiring all of the needed MVC components used for displaying the page the user requested. By filter all requests to a single file, we are able to use a development approach similar to traditional software development. So you can think of the index.php as your main class. Now we require three classes. The first is the Router class; this class is responsible for parsing the request GET variable and including a controller class and calling a method of this controller class based on the this GET variable data. The second is the Registry class; this class stores application variables used by the framework. The third class is the Template class; this class will both store variables assigned by the controller for the view to use and include the view itself.
The bootstrapping process also provides: the instantiation of a Router, Registry and Template class instance; the call to the router instances route method; and a __autoload method for any model class that may be used by the controller classes.
index.php
<?php
require_once('application/Router.php');
require_once('application/Registry.php');
require_once('application/Template.php');
$router = new Router();
$registry = new Registry();
$registry->template = new Template();
$router->route($registry);
/*** auto load model classes ***/
function __autoload($class_name)
{
try
{
$filename = strtolower($class_name) . '.php';
$file = 'application/models/' . $filename;
if (file_exists($file))
include ($file);
else
throw new Exception('model ' . $class_name . '.php not found');
}
catch(Exception $e)
{
echo $e->getMessage();
exit(0);
}
}
The Router Class
As you can see the __construct method parses the request variable assigning the value of index if any part is null. This would be the case if index.php is the file the user actually requested in the case of the controller being called, and the case for the action of the controller if the requested is for a directory’s default file.
The route method itself is passed a reference to the registry file, which in turn is passed to the constructor of the controller class. This registry at very least will contain a reference to the template class. Again, what this method does is include the controller first and then call one of its methods. The request var is exploded by the delimited ‘/’ the first element of returned array is the name of the controller and second is the name of the method to be called from the controller. In other words it you request www.yoursite.com: the index method of your indexController would be called. If your requested www.yoursite.com/city: the index method of your cityController would be called. Now if you requested www.yoursite.com/city/cleveland: the cleveland method of your cityController would be called.
Notice that if the controller requested doesn’t exist an Error404Controller is included instead, and has its index method called. This is the controller class for your custom 404 page.
Router.php
<?php
class Router
{
private $path, $controller, $action;
static $instance;
public function __construct()
{
$request = $_GET['request'];
$split = explode('/',trim($request,'/'));
$this->controller = !empty($split[0]) ? ucfirst($split[0]) : 'Index';
$this->action = !empty($split[1]) ? $split[1] : 'index';
}
public function route($registry)
{
require_once('application/BaseController.php');
$file = 'application/controllers/' . $this->controller . 'Controller.php';
if(is_readable($file))
{
include $file;
$class = $this->controller . 'Controller';
}
else
{
include 'application/controllers/Error404Controller.php';
$class = 'Error404Controller';
}
$controller = new $class($registry);
if (is_callable(array($controller, $this->action)))
$action = $this->action;
else
$action = 'index';
$controller->$action();
}
}
controllers
First here is the abstract BaseController class which holds a protected reference to the registry reference and demands and index method exists in all subclasses.
BaseController.php
<?php
abstract class BaseController
{
protected $registry;
function __construct($registry)
{
$this->registry = $registry;
}
abstract function index();
}
The concrete controller classes’ role is to provide the interface between to model data and view. For this example, I am only showing a one way interaction; the controller is getting data from the model to be displayed by the view. This is done by adding variables to the template class that the view will need to use.
Notice how there is no require of include needed for the TestModel class. This is because of the __autoload function in the index.php file. It automatically includes the model classes if they are not present.
IndexController.php
<?php
class IndexController extends BaseController
{
public function index()
{
$this->registry->template->test = $this->getModelData();
$this->registry->template->show('indexView.php');
}
private function getModelData()
{
$model = TestModel::getInstance();
return $model->getData();
}
}
models
Here you will generally interacting with a database. For this example I am just returning a string to show the full model to view interaction via the controller.
TestModel.php
<?php
class TestModel
{
private $testData = 'data from the model';
static $instance;
public static function getInstance()
{
if(self::$instance == null)
self::$instance = new self();
return self::$instance;
}
private function __construct(){}
private function __clone(){}
public function getData()
{
return $this->testData;
}
}
views
The template class is responsible for including the view the controller sends as a parameter as well as providing this newly included file access to the template variables set by the controller. This is all done in the show method.
Template.php
<?php
class Template
{
private $vars = array();
public function __set($index, $value)
{
$this->vars[$index] = $value;
}
public function show($viewName)
{
try
{
$file = 'application/views/' . $viewName;
if (!file_exists($file))
throw new Exception('View ' . $viewName . ' not found.'); else
foreach ($this->vars as $key => $value)
{
$$key = $value;
}
include($file);
}
catch(Exception $e)
{
echo $e->getMessage();
exit(0);
}
}
}
A view itself is not a class but a PHP page with PHP blocks used only to display template variables for dynamic data provided by the controller. The variables data should not need to be further parsed or manipulated at this point; that was the responsibility of the controller.
indexView.php
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Untitled Document</title> </head> <body> <h1>Test Page</h1> <p> <?php echo $test; ?> </p> </body> </html>
Summary
There you have it, a quick run though of how to build and implement your own MVC framework. Design Patterns.