Hand-writing your own PHP MVC Framework Example Tutorial

Source: Internet
Author: User
Tags learn php php foreach

1 What is MVC

The MVC pattern (model-view-controller) is a software architecture model in software engineering, which divides the software system into three basic parts: model, view and controller.

The purpose of the MVC pattern is to implement a dynamic program design that simplifies the subsequent modification and expansion of the program, and makes it possible to reuse a part of the program. In addition, this mode makes the program structure more intuitive by simplifying the complexity. By separating the basic parts of the software system, it also gives the functions of each basic part.

Nutshell

    • Model -manages all database -related logic. The model provides an abstraction layer for connecting and manipulating databases.
    • Controller Controllers -responsible for all business logic , such as if/else logic.
    • views View – Responsible for interface display, such as Hmtl/xml/json display.

2 Why you should develop your own MVC framework

There are a number of excellent MVC frameworks available on the Web, and this tutorial is not intended to develop a comprehensive, ultimate MVC framework solution, but to consider it as a good opportunity to learn PHP from the inside, and in the process you will learn object-oriented programming and MVC design Patterns , and learn some of the considerations in development.

More importantly, you can take full control of your framework and incorporate your ideas into your development framework. Although not necessarily a good one, you can develop features and modules in your own way.

3 start to develop your own MVC framework

3.1 Directory Preparation

Before starting the development, let's set up the project first, assuming that the project we built for the TODO,MVC framework can be named Fastphp, then the first step is to set the directory structure first.

Although all of the above directories are not used in this tutorial, it is necessary to set up the program directory at the outset in order to extend the program's extensibility. Here's what each directory is about:

    • Application – Application code
    • Config – program configuration or database configuration
    • fastphp -Framework Core Catalog
    • public – Static files
    • Runtime -Temp Data Directory
    • Scripts – command line tools

3.2 Code Specification

After the catalog has been set up, we're going to specify the code specification:

    1. MySQL's table name should be lowercase , such as: Item,car
    2. The module name (Models) needs to be capitalized , and a "Model" is added after the name, such as: Itemmodel,carmodel
    3. The controller (Controllers) needs to be capitalized , and adds "controller" to the name, such as: Itemscontroller,carscontroller
    4. View (views) The deployment structure is "controller name/behavior name", such as: item/view.php,car/buy.php

Some of the rules above are designed to make better calls to each other in the program. The next step is to start real PHP MVC programming.

3.3 Redirects

Redirect all data requests to the index.php file and create a new . htaccess file in the Todo directory with the following file contents:

 
  
   
      Rewriteengine on    # Make sure the request path is not a file name or directory    rewritecond%{request_filename}!-f    Rewritecond%{request_filename} !-d    # REDIRECT all requests to Index.php?url=pathname    rewriterule ^ (. *) $ index.php?url=$1 [pt,l]
 
  

The main reasons for this are:

    1. The program has a single entrance;
    2. In addition to the static program, all other programs are redirected to index.php;
    3. can be used to generate SEO-conducive URLs, want to better configure the URL, late may need URL routing, here do not introduce.

3.4 Entry File

Finish the above operation, you should know what we need to do, yes! In the public directory, add the index.php file with the following file contents:

    

Note that the PHP code above does not add the PHP end symbol "?>", so the main reason for this is that for files with only PHP code, the end flag ("?>") best not exist, PHP itself does not need to end the symbol, Not adding a closing symbol can largely prevent the end from being added with additional injected content, making the program more secure.

3.5 Configuration files and master requests

In index.php, we made a request to fastphp.php under the fastphp folder, so what exactly does fastphp.php This boot file contain?

 
   Run ();

The above files can actually be directly included in the index.php file, constants can also be directly defined in the index.php, we do so for the later management and expansion of the more convenient, so the need to load the run at the beginning of the program is unified into a separate file reference.

First look at the config file under Config. php file, the main role of the file is to set some program configuration items and database connection, the main content is:

     

It should be said that config.php involved in a few things, but some basic database settings, and then see fastphp under the Common Framework portal file core.php should be how to write.

   Setreporting ();        $this->removemagicquotes ();        $this->unregisterglobals ();    $this->callhook ();            }//Master request method, the main purpose is to split the URL request function Callhook () {if (!empty ($_get[' url '))) {$url = $_get[' url '];                        $urlArray = Explode ("/", $url); Get controller name $controllerName = Ucfirst (Empty ($urlArray [0])?            ' Index ': $urlArray [0]); $controller = $controllerName.                        ' Controller ';            Gets the action name Array_shift ($urlArray); $action = Empty ($urlArray [0])?                        ' Index ': $urlArray [0];            Gets the URL parameter array_shift ($urlArray); $queryString = Empty ($urlArray)?        Array (): $urlArray; }//data is empty processing $action = Empty ($action)?        ' Index ': $action; $queryString = Empty ($queryString)?                Array (): $queryString;            Instantiate controller $int = new $controller ($controllerName, $action); If a controller exists and the action is present, this calls and passes in the URLparameter if ((int) method_exists ($controller, $action)) {Call_user_func_array (Array ($int, $action), $queryStri        NG); } else {exit ($controller.        "Controller does not exist"); }}//Detect development environment function setreporting () {if (App_debug = = True) {error_reporting (E_all            );        Ini_set (' display_errors ', ' on ');            } else {error_reporting (e_all);            Ini_set (' display_errors ', ' Off ');            Ini_set (' log_errors ', ' on '); Ini_set (' Error_log ', Runtime_path.        ' Logs/error.log '); }}//delete sensitive character function stripslashesdeep ($value) {$value = Is_array ($value)? Array_map (' Stripslashes        Deep ', $value): Stripslashes ($value);    return $value; }//detects sensitive characters and removes function removemagicquotes () {if (GET_MAGIC_QUOTES_GPC ()) {$_get = Stripslashe            Sdeep ($_get);            $_post = Stripslashesdeep ($_post);            $_cookie = Stripslashesdeep ($_cookie); $_sEssion = Stripslashesdeep ($_session);  }}//Detect custom global variable (register globals) and remove function unregisterglobals () {if (Ini_get (' register_globals '))           {$array = array (' _session ', ' _post ', ' _get ', ' _cookie ', ' _request ', ' _server ', ' _env ', ' _files '); foreach ($array as $value) {foreach ($GLOBALS [$value] as $key = + $var) {if ($var = =                    = $GLOBALS [$key]) {unset ($GLOBALS [$key]); }}}}}//Auto load Controller and model class static function LoadClass ($class) {$framew Orks = ROOT. $class.        EXT; $controllers = App_path. ' application/controllers/'. $class.        EXT; $models = App_path. ' application/models/'. $class.        EXT;        if (file_exists ($frameworks)) {//Load frame core class include $frameworks;        } elseif (File_exists ($controllers)) {//Load the application controller class include $controllers; } elseif (fIle_exists ($models)) {//Load Application model class include $models; } else {/* error code */}}}

The following focuses on the main request method Callhook (), first we want to see our URL will be like this:

Yoursite.com/controllername/actionname/querystring

The function of Callhook () is to get the URL from the global variable $_get[' URL ' variable and split it into three parts: $controller, $action, and $queryString.

For example, the URL link is: Todo.com/item/view/1/first-item, then

    • $controller is: items
    • $action is: view
    • Query string: Array (1, First-item)

When the partition is complete, a new controller is instantiated: $controller. ' Controller ' (where ".") is a hyphen) and calls its method $action.

3.6 Controller/controller base class

The next step is to build the base classes required for the program in fastphp , including the base classes for controllers , models , and views .

The new Controller base class is Controller.class.php , the main function of the controller is the total scheduling, the specific content is as follows:

 
    _controller = $controller;        $this->_action = $action;        $this->_view = new View ($controller, $action);    }     function set ($name, $value) {        $this->_view->set ($name, $value);    }     function __destruct () {        $this->_view->render ();    }         }

The Controller class implements communication for all controllers, models, and Views (view classes). When the destructor is executed, we can call render () to display the view file.

3.7 Model base class

The new model base class is Model.class.php , and the model base class Model.class.php code is as follows:

 
    Connect (db_host,db_user,db_password,db_name);                The conversion model +model the name of the model                        //Gets the names of the classes to which the object belongs        $this->_model = Get_class ($this);        $this->_model = RTrim ($this->_model, ' model ');                The database table name is consistent with the class name        $this->_table = strtolower ($this->_model);    }     function __destruct () {    }}

Considering that the model needs to process the database , a separate database base class Sql.class.php is created, and the model base class inherits Sql.class.php, the code is as follows:

   _dbhandle = @mysql_connect ($address, $account, $pwd);            if ($this->_dbhandle! = 0) {if (mysql_select_db ($name, $this->_dbhandle)) {return 1;            } else {return 0;        }} else {return 0; }}/** disconnected from database **/function disconnect () {if (@mysql_close ($this->_dbhandle)! = 0) {retur        n 1;        } else {return 0; }}/** queries all **/function SelectAll () {$query = ' select * from '. $this->_table. '        `';    return $this->query ($query); The/** query **/function Select ($id) {$query = ' select * from ' $this based on the condition (ID).->_table. ' ' WHERE ' id ' = \ '. mysql_real_escape_string ($id). '        \'';    return $this->query ($query, 1); /** Delete the **/function Delete ($id) {$query = ' delete from ', based on the condition (ID). $this->_table. ' ' WHERE ' id ' = \ '. mysql_real_escape_string ($id). '     \'';   return $this->query ($query); }/** the custom SQL query **/function query ($query, $singleResult = 0) {$this->_result = mysql_query ($query,         $this->_dbhandle);        if (Preg_match ("/select/i", $query)) {$result = array ();        $table = Array ();        $field = Array ();        $tempResults = Array ();        $numOfFields = Mysql_num_fields ($this->_result);            for ($i = 0; $i < $numOfFields; + + $i) {Array_push ($table, mysql_field_table ($this->_result, $i));        Array_push ($field, Mysql_field_name ($this->_result, $i)); } while ($row = mysql_fetch_row ($this->_result)) {for ($i = 0; $i < $numOfFields ; + + $i) {$table [$i] = Ucfirst ($table [$i]); $tempResults [$table [$i]][$field [$i]] = $row [$i];} if ($singleResult = = 1) {Mys                    Ql_free_result ($this->_result);                return $tempResults;            } array_push ($result, $tempResults); } MySQL_free_result ($this->_result);        return ($result);    }}/** gets the number of records **/function Getnumrows () {return mysql_num_rows ($this->_result);    /** Release Query resource **/function Freeresult () {mysql_free_result ($this->_result);    }/** get error message **/function GetError () {return mysql_error ($this->_dbhandle); }    }

It should be said that Sql.class.php is a core part of the framework . Why? Because of this, we created a SQL abstraction layer, which greatly reduces the programming of the database. The Connect () and disconnect () methods are relatively simple and do not explain more, focusing on query queries. Suppose we have the following SQL query statement:

SELECT table1.field1, Table1.field2, Table2.field3, table2.field4 from Table1,table2 WHERE ...

If you use the SQL base class above, the first thing to do is to select the fields to output and the corresponding data tables, and then put them in the array, where $field and $table use the same index values. In the example above, they are:

$field = Array (field1,field2,field3,field4); $table = Array (table1,table1,table2,table2);

The script expands all the rows of data and transforms the data table into a model name (such as removing complex numbers and first letter capitalization). The result of the query is finally saved in a multidimensional array and then returned in a format similar to: $var [' modelname '] [' fieldName '] . This way, the output can be very easy to use in the view.

3.8 Views View class

The View.class.php contents of the view class are as follows:

   _controller = $controller;    $this->_action = $action;    }/** Set Variable method **/function set ($name, $value) {$this->variables[$name] = $value;        }/** displays **/function render () {Extract ($this->variables); $defaultHeader = App_path.        ' application/views/header.php '; $defaultFooter = App_path.        ' application/views/footer.php '; $controllerHeader = App_path. ' application/views/'. $this->_controller.        '/header.php '; $controllerFooter = App_path. ' application/views/'. $this->_controller.                '/footer.php ';        Page header file if (file_exists ($controllerHeader)) {include ($controllerHeader);        } else {include ($defaultHeader); }//page content file include (App_path. ' application/views/'. $this->_controller. '/' . $this->_action.                '. php ');        Footer file if (file_exists ($controllerFooter)) {include ($controllerFooter); } else {include ($defaultFooter); }    } }

So our core PHP MVC framework is written, and here we start writing apps to test the framework functionality.

4 applications

4.1 Database Deployment

Create a new TODO database in SQL and use the following statement to increase the item data table and insert 2 records:

CREATE TABLE ' Items ' (    ' id ' int (one) ' NOT null auto_increment,    ' item_name ' varchar (255) is not NULL,    PRIMARY KEY (' ID ')); INSERT into ' Items ' VALUES (1, ' Hello World '); Nsert into ' Items ' VALUES (2, ' Lets go! ');

4.2 Deployment of models

Then we also need to create a itemmodel.php model in the models directory, with the following content:

 
    _table. ' ' (item_name) VALUES (\ ". mysql_real_escape_string ($value). ' \')';        return $this->query ($query);    }    /** New Data **/    function Update ($id, $value) {        $query = ' Update '. $this->_table. ' ' Set item_name = \ '. mysql_real_escape_string ($value). ' \ ' where ' id ' = \ '. mysql_real_escape_string ($id). ' \'';        return $this->query ($query);    }    }

The model content is empty. Because the Item model inherits models, it has all the features of model.

4.3 Deployment of the Controller

Create a itemscontroller.php controller in the controllers directory with the following contents:

   Set (' title ', ' all entries ');    $this->set (' Todo ', $item->query (' SELECT * from item '));        }//Add record, test framework DB record creation (create) function add () {$value = $_post[' value '];        $item = new Itemmodel;        $this->set (' title ', ' Add success ');    $this->set (' Todo ', $item->add ($value));        }//view record, test framework DB record read (read) function view ($id = null, $name = null) {$item = new Itemmodel;        $this->set (' title ', ' viewing '. $name);    $this->set (' Todo ', $item->select ($id));        }//update record, test framework DB Record update (updated) function update () {$id = $_post[' id '];        $value = $_post[' value '];        $item = new Itemmodel;        $this->set (' title ', ' modified success ');    $this->set (' Todo ', $item->update ($id, $value));        }//delete record, test framework DB record Delete (delete) function Delete ($id = null) {$item = new Itemmodel;        $this->set (' title ', ' delete succeeded ');    $this->set (' Todo ', $item->delete ($id)); } }

4.4 View of the deployment

Create a new header.php and footer.php two header footer templates in the Views directory, as follows.

header.php , content:

    
   
    
       <title><?php Echo $title?></title>        

footer.php , content:

Then, create the following view files in Views/item .

index.php , browse all records of the item table in the database, content:



/ " > ---- " > Delete

add.php , adding a record, content:

Add success, click Back

view.php , view a single record, content:

Return

update.php , change record, content:

Change success, click Back

delete.php , deleting records, Contents:

Delete success, click Back

4.5 Application Testing

This way, in the browser to access the TODO program: http://localhost/todo/item/index/, you can see the effect.

All of the above code is posted on my GitHub, code warehouse address: Https://github.com/yeszao/FastPHP, Welcome to clone, submit.

This article refers to:

    • http://anantgarg.com/2009/03/13/write-your-own-php-mvc-framework-part-1/
  • Contact Us

    The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

    If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.