Creating a PHP5 Framework – Part 1

With websites becoming more and more dynamic and interactive, developers often look to frameworks to help build websites and web apps rapidly. While there are a number of great frameworks available, a custom framework gives you the ability to easily customize the framework as you need, and to build with it even quicker – as you would already know the ins and outs of it before working with it. In this series of tutorials, we are going to build our very own PHP5 Development Framework! Let’s start with planning our framework and put the basic structure into place.

*Note – Running the demo should display “PCA Framework version 0.1 the HTML output” – which demonstrates the first stage of our framework.

Step 1: This Series

In this series, we will create our own PHP5 Framework from scratch. The Framework will include basic content management features, and we will use it to build a web-based directory for a small organization.

Hopefully, as we go along, you will improve, build up and optimize this framework to suite your needs better, however in these tutorials we are aiming to get a simple framework up and running and powering a website.

Over the next few weeks, during these tutorials we will cover:

  • Creating authentication handler, database abstraction layer and template manager
  • Bringing these objects together
  • Using the framework to manage content, and power our site
  • Creating a fantastic front end design.
  • Designing for the login process by storyboarding
  • How the Framework can be extended and expanded

Step 2: Design Patterns and their use within our Framework

When creating any large computer-based system, be it a desktop application, a distributed network system, or a web application there will always be architectural challenges associated with its implementation.

Design patterns address some of these common problems, and we will make use of a number of design patterns as we create our Framework, to ensure that we have a quality, flexible, robust and usable framework, fit for any purpose! In particular, in this tutorial we are going to look at the Singleton pattern and the Registry pattern.

Step 3: Files and Folders

The first thing to get started creating our Framework, is to create a suitable file structure, such that everything has its place. As well as the files powering the framework, we also need to make provisions for files relating to the website we are going to create with our framework. Most websites and web applications have:

  • Some commonly used functions / objects.
  • Business logic.
  • A design

This gives us a great starting point, files relating to each of those three categories should be grouped together in their own section. Take a look at the directory structure below, we will then discuss the reasons for the structure.

Note that the .settings folder and the .project file were created by the IDE I use, and don’t need to be present in your application

Core functions and objects, such as database access, authentication, template handling, email sending objects, email parsing objects, should be stored within a folder called objects, within the PCARegistry folder. This allows us to separate the logic from the Registry (which we will look at shortly) from the objects stored within the Registry.

Next, we need somewhere to store our business logic which is the files we will create which make use of our framework. We should keep these files in a folder called controllers. Each major function that our website or web application does (e.g. business directory listing, providing and managing content, providing an image gallery, etc) would be a separate controller, stored within its own folder within the controllers folder. We are not going to use these in this tutorial, but it is important to have our directory structure in place, so we know how it will work.

The sites design and templates, should be stored within the skins folder. Since we may want different designs (either so users of the application/website we create with our framework can chose from a number of designs, or to change the design depending on season or special event), each skin will be contained within its own folder.

Step 4: The Registry

At the heart of our framework we will have the core functions, such as database access, user authentication, etc. By implementing the Registry design pattern, we can keep these objects stored centrally, within the Registry, making it easy for our Framework and any applications which utilize our framework to access.

The registry design pattern stores and retrieves references to objects, and works in a similar way to a telephone directory: storing and retrieving contacts. We will use it to store these core objects, system-wide settings, and later, any other data or information which needs to be shared across the system.

Because we are storing this information centrally, we only ever want one instance of this registry object to be available within our framework, if more than one were available, then we would have problems where we were expecting a certain piece of data, or a certain object to be in the registry, when it was in fact stored within another instance of the Registry object. To solve this problem, our Registry object will also implement the Singleton design pattern, which prevents more than a single instance of the object being available.

Below is the PHP code for the registry.class.php file, we will look into how it works shortly.

<?php
/**
 * The PCARegistry object
 * Implements the Registry and Singleton design patterns
 *
 * @version 0.1
 * @author Michael Peacock
 */
class PCARegistry {

	/**
	 * Our array of objects
	 * @access private
	 */
	private static $objects = array();

	/**
	 * Our array of settings
	 * @access private
	 */
	private static $settings = array();

	/**
	 * The frameworks human readable name
	 * @access private
	 */
	private static $frameworkName = 'PCA Framework version 0.1';

	/**
	 * The instance of the registry
	 * @access private
	 */
	private static $instance;

	/**
	 * Private constructor to prevent it being created directly
	 * @access private
	 */
	private function __construct()
	{

	}

	/**
	 * singleton method used to access the object
	 * @access public
	 * @return
	 */
	public static function singleton()
	{
		if( !isset( self::$instance ) )
		{
			$obj = __CLASS__;
			self::$instance = new $obj;
		}

		return self::$instance;
	}

	/**
	 * prevent cloning of the object: issues an E_USER_ERROR if this is attempted
	 */
	public function __clone()
	{
		trigger_error( 'Cloning the registry is not permitted', E_USER_ERROR );
	}

	/**
	 * Stores an object in the registry
	 * @param String $object the name of the object
	 * @param String $key the key for the array
	 * @return void
	 */
	public function storeObject( $object, $key )
	{
		require_once('objects/' . $object . '.class.php');
		self::$objects[ $key ] = new $object( self::$instance );
	}

	/**
	 * Gets an object from the registry
	 * @param String $key the array key
	 * @return object
	 */
	public function getObject( $key )
	{
		if( is_object ( self::$objects[ $key ] ) )
		{
			return self::$objects[ $key ];
		}
	}

	/**
	 * Stores settings in the registry
	 * @param String $data
	 * @param String $key the key for the array
	 * @return void
	 */
	public function storeSetting( $data, $key )
	{
		self::$settings[ $key ] = $data;

	}

	/**
	 * Gets a setting from the registry
	 * @param String $key the key in the array
	 * @return void
	 */
	public function getSetting( $key )
	{
		return self::$settings[ $key ];
	}

	/**
	 * Gets the frameworks name
	 * @return String
	 */
	public function getFrameworkName()
	{
		return self::$frameworkName;
	}

}

?>

So, how does the Registry object work, and how does it keep our objects stored nicely?

  • Objects are stored within an array.
  • When a new object is stored within the Registry, the class file is included, the object is instantiated and then it is stored in the array.
  • Objects are retrived by passing the objects “key” to the getObject method.

How does it prevent another copy of the Registry object being created?

  • The constructor is private, preventing the object from being created directly.
  • Cloning the object triggers an error.
  • If we need to access the object from within our Framework, and it is not directly available to the file we are working in, we can call the static method singleton ( PCARegistry::singleton() ) to get the instance of the Registry.

Step 5: index.php

With the structure in place ready for the core functionality which we will add in a further tutorial, let’s look at how we will access the Registry, and start work on our Frameworks single point of access, our index.php file.

Friendly URLs are commonly available in all forms of dynamic websites and web applications, and one of the simplest ways to do this (and to manage the control of information through our Framework) is to ensure all of our page requests go through the index.php file. In a later tutorial, we will create a .htaccess file to redirect requests from a nice, friendly format, into a format that our index.php file can understand.

The index.php file’s code is below. It doesn’t do a lot at the moment, but it allows us to get things in place.

<?php
/**
 * PCAFramework
 * Framework loader - acts as a single point of access to the Framework
 *
 * @version 0.1
 * @author Michael Peacock
 */

// first and foremost, start our sessions
session_start();

// setup some definitions
// The applications root path, so we can easily get this path from files located in other folders
define( "APP_PATH", dirname( __FILE__ ) ."/" );
// We will use this to ensure scripts are not called from outside of the framework
define( "PCAFW", true );

/**
 * Magic autoload function
 * used to include the appropriate -controller- files when they are needed
 * @param String the name of the class
 */
function __autoload( $class_name )
{
	require_once('controllers/' . $class_name . '/' . $class_name . '.php' );
}

// require our registry
require_once('PCARegistry/pcaregistry.class.php');
$registry = PCARegistry::singleton();

// print out the frameworks name - just to check everything is working
print $registry->getFrameworkName();

exit();

?>

So…what does our index.php file do at the moment? It:

  • Calls start_session right away, to ensure we can use sessions throughout the Framework (this must be called before any output.
  • It creates a definition of the current file path, so we can reference the frameworks root directory from elsewhere, and it creates a definition that we will use to ensure all of the Frameworks files are being called from the Framework itself, and that someone isn’t trying to call one of the files directly
  • It uses the autoload function to determine where any classes may be located. In this case, it points to the controllers directory, as this is where our business logic will be stored.
  • It includes the registry class (this is needed as the class is not within the controllers folder where the autoload function would find it, and references the instance of the Registry to the variable $registry.
  • Finally, it prints out the name of the framework, to demonstrate a simple function from within the Registry.

We can see in more detail how the Registry will work within our Framework – by creating some dummy class files for it to use. With a template class in a new template.class.php file in the PCARegsitry/objects folder, we can demonstrate this, by adding some additional code to our index.php file.

On the line after we first reference $registry, we could add:

$registry->storeObject('template','template');

If our template class had a method contained within it, such as generateOutput, we could call this method from index.php like so:

$registry->getObject('template')->generateOutput();

Our Framework now has a basic structure to it, and we have a Registry in place for our core functionality, in the next tutorial, we will look at creating the objects which our Registry will store, starting with a basic database abstraction layer and a security manager.

Related Posts

Add Comment

Discussion 95 Comments

Comment Page 3 of 3 1 2 3
  1. Robin says:

    This is really a great post. I can’t wait to see where it goes. I’m also happy to work along with this tutorial since it is one of the few I’ve seen sans anything WordPress. A CMS from scratch. A great idea.
    Thanks.

  2. Evodesign says:

    When comes the 2nd part?

    =D

  3. Sascha says:

    WOW! Can’t wait for part 2 :)

  4. Maako says:

    Okey – now this is some advance tutorial what I’ve been looking for for awhile!

    Can’t wait more! Thanks…

  5. ThinkSoJoE says:

    So, any word on when the next part is going to be? I’ve been looking forward to it since this part came out!

  6. Soon :-) I’m working on it!

  7. ThinkSoJoE says:

    wow – wasn’t expecting an answer so quickly! Thanks!

  8. Ach says:

    Really really great work. Anxiously awaiting the next batch.

  9. John says:

    Come on, the suspense is killing me! When’s the next part out??

  10. insic says:

    i cant wait the next part. part II please

  11. spoontacks says:

    What IDE are you using in this tutorial? Or at least, what is a good IDE to use for PHP?

    (Anyone else who would like to answer, please feel free to do so.)

  12. enrizuu says:

    This is very interesting….
    Where is the SECOND PART?

  13. insic says:

    @spoontacks ZEND IDE rocks. But if you want free you can try Aptana, NetBeans just down load the php plugin. Enjoy…

  14. Sajhu says:

    Great! thanks, waiting for te next part!

  15. EllisGL says:

    Very nice – but a couple of things could be optimized and more secured.

    I’ll talk about the later. Securing the session:
    session_start();

    /**
    * Secure the session – Basic
    */
    if(isset($_SESSION['HTTP_USER_AGENT']))
    {
    if($_SESSION['HTTP_USER_AGENT'] != md5($_SERVER['HTTP_USER_AGENT']))
    {
    session_regenerate_id();
    $_SESSION['HTTP_USER_AGENT'] = md5($_SERVER['HTTP_USER_AGENT']);
    }
    }
    else
    {
    $_SESSION['HTTP_USER_AGENT'] = md5($_SERVER['HTTP_USER_AGENT']);
    }

  16. Robin Card says:

    Hi Nice tutorial but one amendment.

    # The constructor is private, preventing the object from being created directly.
    # Cloning the object triggers an error.
    Why not just declare the class as an abstract?

    # abstract class PCARegistry {

  17. hdragomir says:

    You hear so much about the MVC design pattern, yet there’s so little information on how to actually implement it. This tutorial is a great stating point for many young developers.
    Great job!

  18. Adrian says:

    Eagerly waiting for the second part!

  19. Anuj Seth says:

    Wonderful tutorial. I just completed reading Part 1 & 2.

    Just wondering though…why reinvent the wheel? What is the drawback of using frameworks like CodeIgnitor or CakePHP?

  20. Aditya says:

    YOU ARE A ROCKSTAR, Mike!!! Awesome tut, I can’t thank you enough! And also many thanks to Nettuts, who not only brought up this framework of awesomeness to provide these type of tuts, but also refrained from keeping this series in the premium category.

    For those who are whining about re-inventing the wheel, I have this to say: stuff like Registry and Singleton models are not talked about in the normal tuts as they are too advanced, and doing this type of work helps those of us who are not fortunate enough to be computer engineers the more intricate details of programming.

    And, I wanted to say this for a long time now: Insic, you are gorgeous :D

  21. hello, thank you for sharing this information.
    Michael, would enable a tutorial on how to make a CMS

    Sincerely, carlos

  22. Rasmus says:

    Awesome tutorial – love it. But a link in the bottom to part two wouldn’t be that bad.

    How ’bout a few on JavaScript from scratch? Not everybody is so keen on learning javascript the jquery way. ;)

  23. David says:

    Thanks for the tutorials.

    Excuse me, as I’m probably over-looking how to properly use the singleton method, but I have a menu class for generating a side-menu and it complains as it can’t get access to $registry?

    class menu {

    function execute() {

    $query = $registry->getObject(‘query’);

    $this->categories = $query->getAll(‘admincategories’);
    }
    }

    I’ve done a store object for query, loaded by a storeCoreObjects function in the registry class, and I understand why menu can’t access it, as singleton is ran outside of the class, but what’s the best way for menu class to access the query class so I can run getAll?

  24. bigwetbutt says:

    Where’s PART 2? I’m starting to think it’s not coming. I might check back 1 more time…

  25. Paul says:

    In the storeObject function, what is the use of the self::instance in the brackets when creating an object?

    “self::$objects[ $key ] = new $object( self::$instance );

    I couldn’t work out it’s use, so I removed it and everything still works fine!

  26. Ben says:

    Tired of writing lines of lines with source code each time you are coding a website? Feel like just copying and pasting but afraid that you might end up getting sued?
    No more worries, WebCodeBase is the website you’ve been looking for!
    Here you can find source code that you can copy without any issues at all, we guarantee that you will not get sued for using the code we put on this website. So what are you waiting for?

    http://www.webcodebase.com

  27. Ales says:

    I was a long time looking for something like this. The article brings a complex wiew on the topic.

  28. Michael says:

    Definitions and includes IMHO would be better using like this
    define( “DS”, DIRECTORY_SEPARATOR);
    define( “APP_PATH”, dirname( __FILE__ ) .DS );
    require_once(APP_PATH.’PCARegistry’.DS.’pcaregistry.class.php’);
    Those people who using Windows :)

  29. Dave says:

    Is there any way to store an object in this registry class with params in counstructor ?

  30. J says:

    Thank you sir for this tutorial!!
    You are the man.

  31. alex says:

    Do you think you should use the __autoload() magic function instead of this?

    require_once(‘objects/’ . $object . ‘.class.php’);

  32. CgBaran Tuts says:

    Great advanced tutorial thanks

  33. Jesse says:

    Thanks man!

  34. chknkiller says:

    Nice tutorial indeed. But I have a question. Could you tell me which is the editor shown in the picture?

  35. Nikola Maravich says:

    Awesome !
    Can’t wait for 2nd part =)

  36. John Kenwood says:

    Hi I have found a very nice article that explains how MVC can be used and other bloating features of a framework can be eradicated to form a no-framework. Really interesting reads.

    http://www.devlopr.com/do-frameworks-fail-when/

    http://www.devlopr.com/after-all-what-is-this-no-framework/

    http://www.devlopr.com/the-mystery-of-the-dead-project-%E2%80%93-exposed/

  37. PhantomCode says:

    I was just wonder why you format your block comments with the extra asterisk, like this:
    /**
    * Comment
    */
    rather than this:
    /*
    * Comment
    */

    Is it just because you think that looks better?

    • Markus says:

      IDE’s like Aptana or Zend Studio recognize those Comments and display them at tooltips when u use one of the functions on another place.

  38. Markus says:

    Why do you prevent cloning of the object in the registry?

  39. Ivan says:

    Tu aporte esta realmente interesante!!
    Me gustaría que siguieran enseñando más acerca de este tema.

    Gracias!

Comment Page 2 of 2 1 2

Add a Comment