ASPit - Totally ASP JSit - Totally JavaScript
Search PHPit

Use this textbox to search for articles on PHPit. Seperate keywords with a space.

Advertisements

Building a simple MVC system with PHP5

(Page 2 out of 5)

Startup Tasks

The startup file is used to do some general startup tasks, like defining constants, setting the error reporting level, etc. The first part of our startup file looks like this:


error_reporting (E_ALL);
if (version_compare(phpversion(), '5.1.0', '<') == true) { die ('PHP5.1 Only'); }

// Constants:
define ('DIRSEP', DIRECTORY_SEPARATOR);

// Get site path
$site_path = realpath(dirname(__FILE__) . DIRSEP . '..' . DIRSEP) . DIRSEP;
define ('site_path', $site_path);

In the above example we define some constants, get the site path, and also check to make sure that the current PHP version is at least 5.1.

The next thing we'll have to do is setup a Registry object to hold all our global data. A registry object is passed around all the individual objects in our MVC system, and is used to transport global data throughout the system without having to use the 'global' keyword or $GLOBALS. Read "Using globals in PHP" for more information on the registry object.

Add the following code to the startup.php file, below the code from the previous example:

$registry = new Registry;

If you now try to run the system, you should get the following error:

Fatal error: Class 'Registry' not found in g:\Projects\PHPit\content\simple mvc php5\demo\includes\startup.php on line 12

Not really a surprise, since we haven't created the Registry class yet, nor have we included a file that contains the Registry class. We could simply include it using the include() function, but let's use one of PHP5's new features: __autoload().

The __autoload() magic function is used to dynamically load classes. Whenever PHP encounters a non-existent class, it will first call the __autoload() function, and only then declare an error. This can be used to load classes on-the-fly.

Put the following code before the previous code example:

// For loading classes
function __autoload($class_name) {
        $filename = strtolower($class_name) . '.php';
        $file = site_path . 'classes' . DIRSEP . $filename;

        if (file_exists($file) == false) {
                return false;
        }

        include ($file);
}

Our __autoload() function takes the class name, passed as an argument, and checks if a similar named file exists in the classes directory. If the file doesn't exist, the function will simply return false and a fatal error will still show up, but if the file does exist, it will be included, which means the class is suddenly there, and no error is thrown.

We haven't created the Registry class yet, which means we still get an error, so let's do something about that.

Creating the Registry class

The Registry class is used to pass global data around between the individual objects, and is actually a really simple class, and needs no more than three small methods.

First, create a new directory called 'classes', and then create a new file called 'registry.php'. Put the following code in the registry.php file:

Class Registry {
        private $vars = array();

}

?>

We now have a skeleton for the Registry class, and all we need to do is add some methods. All the Registry class needs is a set() method, to set data, and a get() method, to get data. Optionally we can also add a remove() method to remove some data. The following three methods will do, and should be added to the Registry class:

function set($key, $var) {
        if (isset($this->vars[$key]) == true) {
                throw new Exception('Unable to set var `' . $key . '`. Already set.');
        }

        $this->vars[$key] = $var;
        return true;
}

function get($key) {
        if (isset($this->vars[$key]) == false) {
                return null;
        }

        return $this->vars[$key];
}

function remove($var) {
        unset($this->vars[$key]);
}

As you can see, these three methods are really basic, and all they do is set, get and unset items from the $vars property. In the set() method we also check if data with that particular key doesn't already exist, and if it does, we throw an exception. This is to protect from accidentally overwriting data.

We now have a fully functional Registry class, but we aren't going to stop here. We're going to use one of SPL's features: ArrayAccess. SPL, which is short for the Standard PHP Library, is a collection of interfaces and classes that are meant to solve standard problems. One of SPL's interfaces, ArrayAccess, can be used to give array access to an object. Consider the following code snippet:

$registry = new Registry;

// Set some data
$registry->set ('name', 'Dennis Pallett');

// Get data, using get()
echo $registry->get ('name');

// Get data, using array access
echo $registry['name']

?>

The array access makes it seem that $registry is an array, even though it's an object. Although ArrayAccess has not real advantages, it means less typing since you don't have to continuously use ->get(). To use ArrayAccess you will first have to change the first line of the class ("Class Registry"), which becomes:

Class Registry Implements ArrayAccess {

The Implements keyword is used to implement an interface, and that's exactly what ArrayAccess is.

By implementing the ArrayAccess interface, the class must also add four new methods:

function offsetExists($offset) {
        return isset($this->vars[$offset]);
}

function offsetGet($offset) {
        return $this->get($offset);
}

function offsetSet($offset, $value) {
        $this->set($offset, $value);
}

function offsetUnset($offset) {
        unset($this->vars[$offset]);
}

These methods should be fairly self-explanatory, and more information can be found in the SPL documentation.

Now that we have implemented ArrayAccess, we can use the object just like an array, as you saw in the previous example and in the following example:

$registry = new Registry;

// Set some data
$registry->['name'] = 'Dennis Pallett';

// Get data, using get()
echo $registry->get ('name');

// Get data, using array access
echo $registry['name']

?>

Our Registry class is now finished, and if you try to run the system everything should work (although nothing is displayed yet). Our startup file is finished, and we can move to the next step of our MVC system: setting up the database functionality, also called the "Model".

« Previous: Introduction & One Point of Entry
Next: The Model & Router Class »



4 Responses to “Building a simple MVC system with PHP5”

  1. Marion DESNAULT Says:

    Hi,
    thanks for this useful article about the MVC system.
    Just to report a problem using function trim in the Router’s setPath method (line 14) under UNIX systems.
    If we give it an absolute path, it will delete the leading / and create problem when checking if this path is a directory.

  2. Solid Says:

    Why you haven’t used the magic overloading methods __set and __get, instead of using registry class? It’s more easy to use __set, __get with static propery, because in future you don’t need to use methods get()/set(). Anyway, I’m using something like you have been described here for compatibility with PHP4. Instead of class static property I’m using container function, because in PHP4 there are no chance to declare static property in class body.

  3. Alexander(Russia) Says:

    Hello, good article about the MVC for starting.

  4. Matthijs Says:

    Pretty cool article Dennis. Thanks. Good to see a relatively easy explanation of an MVC system. The thing with MVC is that the basics is fairly simple. But it can get complicated quickly when you throw in some locators, observers, datamappers and other classes and patterns.

Leave a Reply

About the author
Dennis Pallett is the main contributor to PHPit. He owns several websites, including ASPit and Chill2Music. He is currently still studying.
Article Index
  1. Introduction & One Point of Entry
  2. Startup Tasks & Registry Class
  3. The Model & Router Class
  4. The Controller
  5. The View & Security Measures & Conclusion
Bookmark Article
Download Article
PDF
Download this article as a PDF file