目錄
设置前端控制器index.php
设置路由器router.php(转发用户请求到相应控制器)
Welcome to Our Website!
News
=$data['title'];?>
首頁 後端開發 php教程 开发自各儿PHP MVC框架(一)

开发自各儿PHP MVC框架(一)

Jun 13, 2016 pm 01:14 PM
gt news php quot

开发自己PHP MVC框架(一)

本教程翻译自John Squibb 的Build a PHP MVC Framework in an Hour,但有所改动,原文地址:http://johnsquibb.com/tutorials

这个教程可以使大家掌握用mvc模式开发php应用的基本概念。此教程分为三个部分,现在这篇是第一部分。

现在市面上有很多流行的框架供大家使用,但是我们也可以自己动手开发一个mvc框架,采用mvc模式可以大大减少我们开发应用的时间,并且能够更好的组织项目源代码,而且其中的某些模块还可在其它项目中使用。现在我要教大家写一个简单的mvc框架。由于这个项目很简单,轻量,所以可能并不是最佳实践,也不具备安全性,还需要大家在实际应用中完善。

所用技术:php,面向对象开发方法。

开始

首先在网站根目录下建立三个文件夹

  • models
  • views
  • controllers

然后在根目录下新建一个文件:

  • index.php

现在项目结构应该像这样

§ 网站根目录

  § index.php

  § models/

  § views/

  § controllers/


index.php是整个web应用的入口点,所有的用户请求都会经过它。我们会写一些代码来把用户请求分派到相应的控制器中,这些控制器存放在controllers文件夹里。之后,我们就可以用下面的方式来实现页面跳转:

  • http://你的域名.com/index.php?page1
  • http://你的域名.com/index.php?page2
  • http://你的域名.com/index.php?page3

设置前端控制器index.php

首先在index.php中定义网站根目录和网站域名,以便在整个应用中访问。

<?php //应用的根目录就是index.php的父目录
define("SERVER_ROOT", dirname(__FILE__));

//你的域名.comm 是你的服务器域名
define('SITE_ROOT' , 'http://你的域名.com');
登入後複製

定义了网站根目录后,在任何php文件中,都能很方便的引用其它目录的php文件,因为index.php是入口文件,这样就能够在整个应用中访问在它之中定义的这些变量。

设置路由器router.php(转发用户请求到相应控制器)

在controllers目录下新建一个文件,名字为“router.php",这个文件用来处理所有页面请求。想像一下你家里的路由器,它负责把internet路由到家中的每个电脑。router.php文件将会获取传入到index.php的页面请求,然后把请求分派给不同的控制器(controllers)。

route.php中的代码:

<?php //获取所有请求
$request = $_SERVER['QUERY_STRING'];
登入後複製

这句代码会获取传入到应用中的请求参数。QUERY_STRING就是”?“后面的所有字符串。

  • http://你的域名.com/index.php?page1

上面的地址会在代码中得到”page1&action=login“,为了把page1和后面的参数分开,我们需要在route.php中继续加入下列代码:

//解析$request变量,得到用户请求的页面(page1)和其它GET变量(&分隔的变量)如一个请求http://你的域名.com/index.php?page1&article=buildawebsite,则被解析为array("page1", "article=buildawebsite")
$parsed = explode('&' , $request);

//用户请求的页面,如上面的page1,为$parsed第一个变量,shift之后,数组为array("article=buildawebsite")
$page = array_shift($parsed);

//剩下的为GET变量,把它们解析出来
$getVars = array();
foreach ($parsed as $argument)
{
    //用"="分隔字符串,左边为变量,右边为值
    list($variable , $value) = split('=' , $argument);
    $getVars[$variable] = $value;
}

//这是测试语句,一会儿会删除
print "The page your requested is '$page'";
print '<br>';
$vars = print_r($getVars, TRUE);
print "The following GET vars were passed to the page:<pre class="brush:php;toolbar:false">".$vars."
登入後複製
"; 现在我们需要在index.php中引入route.php

<?php /**
 * 定义文档路径
 */
define("SERVER_ROOT", dirname(__FILE__));
define('SITE_ROOT' , 'http://你的域名.com');
/** 
 * 引入router.php 
 */
 require_once(SERVER_ROOT . '/controllers/' . 'router.php');
?>
登入後複製
如果顺利的话,你可以打开浏览器输入:


  • http://你的域名.com/index.php?news&article=howtobuildaframework

我们会看到如下输出

The page you requested is 'news'
	The following GET vars were passed to the page:

	Array
	(
		[article] => howtobuildaframework
	)
	
登入後複製

如果没有上述输出,请检查你的服务器配置是否正确,并检查代码是否有错误。

现在来让我们添加一个页面到我们的网站里,这样就可以让router.php来产生一个页面,而不是直接输出上面的信息。


创建一个控制器(controller)

在controllers文件夹里新建一个文件名为“news.php",定义如下的类:

<?php /**
 * 这个文件处理文章的查询,并提供文章
 */
class News_Controller
{
    /**
     * $template变量会保存与此控制器相关的"view(视图)"的文件名,不包括.php后缀 
     */
    public $template = 'news';

    /**
     * 此方法为route.php默认调用
     * 
     * @param array $getVars 传入到index.php的GET变量数组
     */
    public function main(array $getVars)
    {
        //测试代码,以后会删除
        print "We are in news!";
        print '<br/>';
        $vars = print_r($getVars, TRUE);
        print 
        (
            "The following GET vars were passed to this controller:" .
            "<pre class="brush:php;toolbar:false">".$vars."
登入後複製
" ); } }
注意我们把route.php中的测试代码复制过来了,并做了一些修改,我们把它放置在main函数里。现在让我们来修改route.php中的代码:

<?php /**
 * 此文件会把所有的传入参数分派到相应的控制器中
 */

//获取请求参数
$request = $_SERVER['QUERY_STRING'];

//解析请求页面和其它GET变量
$parsed = explode('&' , $request);

//页面是第一个元素
$page = array_shift($parsed);

//剩余的为GET变量,也把它们解析出来
$getVars = array();
foreach ($parsed as $argument)
{
    //split GET vars along '=' symbol to separate variable, values
    list($variable , $value) = split('=' , $argument);
    $getVars[$variable] = $value;
}

//构成控制器文件路径
$target = SERVER_ROOT . '/controllers/' . $page . '.php';

//引入目标文件
if (file_exists($target))
{
    include_once($target);

    //修改page变量,以符合命名规范(如$page="news",我们的约定是首字母大写,控制器的话就在后面加上“<strong>_Controller”,即News_Controller)
    $class = ucfirst($page) . '_Controller';

    //初始化对应的类
    if (class_exists($class))
    {
        $controller = new $class;
    }
    else
    {
        //类的命名正确吗?
        die('class does not exist!');
    }
}
else
{
    //不能在controllers找到此文件
    die('page does not exist!');
}

//一但初始化了控制器,就调用它的默认函数main();
//把get变量传给它
$controller->main($getVars);?>
登入後複製

再次访问http://你的域名.com/index.php?news&article=howtobuildaframework,你将会看到从News_Controller打印出来的信息。注意,我们现在用die()来处理错误,我们可以用其它更好的错误处理来规制它,但现在使用die()足够了,试试访问其它页面如http://你的域名.com/index.php?books,你会看到"page does not exist!"错误。创建一个Model(模型)完善News_Controller。假设我们有一些新闻片段来供读者阅读,那么就需要News_Controller这个控制器去调用一个模型来抓取相关的新闻片段,无论它们是存储在数据库还是文件里。在models文件夹里新建一个文件,“news.php”,代码如下:

<?php /**
 * 新闻模型为新闻控制器做复杂的后台操作
 */
class News_Model
{
    public function __construct()
    {
        print 'I am the news model';
    }
}
登入後複製

现在,我们需要对新闻控制器稍做一些更改,打开controllers里的news.php,把News_Controller类的main函数的代码改为如下,这样,我们就会在“News_Model”初始化时,看到打印在屏幕上的信息:

public function main(array $getVars)
{
    $newsModel = new News_Model;
}
登入後複製
现在刷新页面,你会看到:

Fatal error: Class 'News_Model' not found in /var/www/mvc/controllers/news.php on line xx
	
登入後複製
等一下,这不是我们想要的结果!我们正试图去加载一个不存在的类。那么原因就是我们并没有引入/models/news.php文件。为了解决这个问题,让们重新来看一下router.php,然后在它的顶部添加一些代码:

//当类初始化时,自动引入相关文件
function __autoload($className)
{
    //解析文件名,得到文件的存放路径,如News_Model表示存放在models文件夹里的news.php(这里是作者的命名约定)
    list($filename , $suffix) = split('_' , $className);

    //构成文件路径
    $file = SERVER_ROOT . '/models/' . strtolower($filename) . '.php';

    //获取文件
    if (file_exists($file))
    {
        //引入文件
        include_once($file);        
    }
    else
    {
        //文件不存在
        die("File '$filename' containing class '$className' not found.");    
    }
}
登入後複製
这个函数重载了PHP内置的autoload函数。当我们试图去初始化一个不存在的类时,这个‘魔术方法’允许我们拦截php所执行的动作。通过使用__autoload函数,我们能够告诉php寻找包含此类的文件的位置。假设你遵循了这篇文章中类和文件名的命名约定,那么每当你初始化一个类时,你就不必手动去引入包含此类的文件了!

保存route.php,再刷新一次浏览器,你会看到:

I am the news model
登入後複製

让我们在新闻模型类里定义一些函数来提供文章。现在,我们只简单的定义了一个数组,并保存一些文章,然后提供一个函数,让控制器从中根据标题获取一篇文章。修改models/news.php:


<?php /**
 * 新闻模型为新闻控制器做复杂的后台操作
 *
 */
class News_Model
{
    /**
     * 文章数组. key为文章标题, 值为相应的
     * 文章。
     */
    private $articles = array
    (
        //文章1
        'new' => array
        (
            'title' => 'New Website' ,
            'content' => 'Welcome to the site! We are glad to have you here.'
        )
        ,
        //2
        'mvc' => array
        (
            'title' => 'PHP MVC Frameworks are Awesome!' ,
            'content' => 'It really is very easy. Take it from us!'
        )
        ,
        //3
        'test' => array
        (
            'title' => 'Testing' ,
            'content' => 'This is just a measly test article.'
        )
    );

    public function __construct()
    {
    }

    /**
     * 根据标题获取文章
     * 
     * @param string $articleName
     * 
     * @return array $article
     */
    public function get_article($articleName)
    {
        //从数组中获取文章
        $article = $this->articles[$articleName];
    
        return $article;
    }

}?>

登入後複製
现在修改controllers/news.php中的main函数:

public function main(array $getVars)
{
    $newsModel = new News_Model;
    
    //获取一篇文章
    $article = $newsModel->get_article('test');
    
    print_r($article);
}
登入後複製
现在我们并没有考虑过滤用户输入的问题,因为我们现在只是为了尽快让大家掌握PHP MVC的基本内容,所以我们现在不必太关心这些。

如果访问如下网址:

§ http://yourdomain.com/mvc/index.php?news&article=test

你会看到如下输出:

Array ( [title] => Testing [content] => This is just a measly test article. ) 
登入後複製

创建视图(VIEW

现在我们已经有控制器和模型了,只差一个视图。视图是表现层,它是你的应用中,与用户接触最频繁的部分。之前我提到过,视图是提供与业务逻辑分离的用户接口,有很多方法可以做到这个。你可以使用模板引擎Smarty或其它类似的。你也可以写一个自己的模板引擎,但那肯定是相当艰巨的任务。最后,你可以使用原生php视图。

对于目前来说,php视图足够了。这个就像以前php与html代码混合编程一样,但是有一点不同是,我们的业务逻辑已经和视图分离了。看一下如下代码:

    
    
        <h1 id="Welcome-to-Our-Website">Welcome to Our Website!</h1>
        <hr>
        <h2 id="News">News</h2>
        <h4 id="data-title-gt">=$data['title'];?></h4>
        <p>=$data['content'];?></p>
    

登入後複製

注意,嵌入的php标签利用了PHP 快捷操作符。这样就能够把我们的内容直接输出到HTML里面了。在views文件夹里新建一个文件“news.php”,把上述代码拷贝进来。现在我们有了视图文件,但是我们需要一个与视图交互的方法。在models文件夹里新建一个文件“view.php”,添加如下代码:


<?php /**
 * 在我们的MVC框架中,处理视图的功能
 */
class View_Model
{
    /**
     * 保存赋给视图模板的变量
     */
    private $data = array();

    /**
     * 保存视图渲染状态
     */
    private $render = FALSE;

    /**
     * 加载一个视图模板
     */
    public function __construct($template)
    {
        //构成完整文件路径
        $file = SERVER_ROOT . '/views/' . strtolower($template) . '.php';
    
        if (file_exists($file))
        {
            /**
             * 当模型对象销毁时才能渲染视图
             * 如果现在就渲染视图,那么我们就不能给视图模板赋予变量
             * 所以此处先保存要渲染的视图文件路径
             */
            $this->render = $file;
        }        
    }

    /**
     * 接受从控制器赋予的变量,并保存在data数组中
     * 
     * @param $variable
     * @param $value
     */
    public function assign($variable , $value)
    {
        $this->data[$variable] = $value;
    }

    public function __destruct()
    {
        //把类中的data数组变为该函数的局部变量,以方便在视图模板中使用
        $data = $this->data;
    
        //渲染视图
        include($this->render);
    }
}
登入後複製

现在,最后一件要做的事就是从News_Controller里加载视图。修改controllers/news.php:

<?php /*
 *这个文件处理文章的查询,并产生新闻文章* 
 */
 class News_Controller{ 
    /** 
     * $template变量会保存与此控制器相关的"view(视图)"的文件名,不包括.php后缀
     * 
     */
     public $template = 'news'; 
    /**
     * 此方法为route.php默认调用
     * 
     * @param array $getVars 传入到index.php的GET变量数组 
     */ 
     public function main(array $getVars) {
         $newsModel = new News_Model; 
         //获取一片文章 
         $article = $newsModel->get_article($getVars['article']); 
         //创建一个视图,并传入该控制器的template变量 
         $view = new View_Model($this->template); 
         //把文章数据赋给视图模板 
         $view->assign('title' , $article['title']); 
         $view->assign('content' , $article['content']); 
     }
}
?>
登入後複製


再加载页面,你就能够看到你的视图模板中的变量,已经被正确的替换掉了。好了,你的简单的MVC框架已经搭建好了,下面我会继续讲《开发自己PHP MVC框架(二)》
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1664
14
CakePHP 教程
1423
52
Laravel 教程
1321
25
PHP教程
1269
29
C# 教程
1249
24
PHP和Python:比較兩種流行的編程語言 PHP和Python:比較兩種流行的編程語言 Apr 14, 2025 am 12:13 AM

PHP和Python各有優勢,選擇依據項目需求。 1.PHP適合web開發,尤其快速開發和維護網站。 2.Python適用於數據科學、機器學習和人工智能,語法簡潔,適合初學者。

PHP行動:現實世界中的示例和應用程序 PHP行動:現實世界中的示例和應用程序 Apr 14, 2025 am 12:19 AM

PHP在電子商務、內容管理系統和API開發中廣泛應用。 1)電子商務:用於購物車功能和支付處理。 2)內容管理系統:用於動態內容生成和用戶管理。 3)API開發:用於RESTfulAPI開發和API安全性。通過性能優化和最佳實踐,PHP應用的效率和可維護性得以提升。

PHP:網絡開發的關鍵語言 PHP:網絡開發的關鍵語言 Apr 13, 2025 am 12:08 AM

PHP是一種廣泛應用於服務器端的腳本語言,特別適合web開發。 1.PHP可以嵌入HTML,處理HTTP請求和響應,支持多種數據庫。 2.PHP用於生成動態網頁內容,處理表單數據,訪問數據庫等,具有強大的社區支持和開源資源。 3.PHP是解釋型語言,執行過程包括詞法分析、語法分析、編譯和執行。 4.PHP可以與MySQL結合用於用戶註冊系統等高級應用。 5.調試PHP時,可使用error_reporting()和var_dump()等函數。 6.優化PHP代碼可通過緩存機制、優化數據庫查詢和使用內置函數。 7

PHP的持久相關性:它還活著嗎? PHP的持久相關性:它還活著嗎? Apr 14, 2025 am 12:12 AM

PHP仍然具有活力,其在現代編程領域中依然佔據重要地位。 1)PHP的簡單易學和強大社區支持使其在Web開發中廣泛應用;2)其靈活性和穩定性使其在處理Web表單、數據庫操作和文件處理等方面表現出色;3)PHP不斷進化和優化,適用於初學者和經驗豐富的開發者。

PHP與Python:了解差異 PHP與Python:了解差異 Apr 11, 2025 am 12:15 AM

PHP和Python各有優勢,選擇應基於項目需求。 1.PHP適合web開發,語法簡單,執行效率高。 2.Python適用於數據科學和機器學習,語法簡潔,庫豐富。

PHP和Python:代碼示例和比較 PHP和Python:代碼示例和比較 Apr 15, 2025 am 12:07 AM

PHP和Python各有優劣,選擇取決於項目需求和個人偏好。 1.PHP適合快速開發和維護大型Web應用。 2.Python在數據科學和機器學習領域佔據主導地位。

PHP與其他語言:比較 PHP與其他語言:比較 Apr 13, 2025 am 12:19 AM

PHP適合web開發,特別是在快速開發和處理動態內容方面表現出色,但不擅長數據科學和企業級應用。與Python相比,PHP在web開發中更具優勢,但在數據科學領域不如Python;與Java相比,PHP在企業級應用中表現較差,但在web開發中更靈活;與JavaScript相比,PHP在後端開發中更簡潔,但在前端開發中不如JavaScript。

PHP和Python:解釋了不同的範例 PHP和Python:解釋了不同的範例 Apr 18, 2025 am 12:26 AM

PHP主要是過程式編程,但也支持面向對象編程(OOP);Python支持多種範式,包括OOP、函數式和過程式編程。 PHP適合web開發,Python適用於多種應用,如數據分析和機器學習。

See all articles