찾다
백엔드 개발PHP 튜토리얼开发自各儿PHP MVC框架(一)

开发自己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으로 문의하세요.
PHP 세션이 실패 할 수있는 몇 가지 일반적인 문제는 무엇입니까?PHP 세션이 실패 할 수있는 몇 가지 일반적인 문제는 무엇입니까?Apr 25, 2025 am 12:16 AM

phpsession 실패 이유에는 구성 오류, 쿠키 문제 및 세션 만료가 포함됩니다. 1. 구성 오류 : 올바른 세션을 확인하고 설정합니다. 2. 쿠키 문제 : 쿠키가 올바르게 설정되어 있는지 확인하십시오. 3. 세션 만료 : 세션 시간을 연장하기 위해 세션을 조정합니다 .GC_MAXLIFETIME 값을 조정하십시오.

PHP의 세션 관련 문제를 어떻게 디버그합니까?PHP의 세션 관련 문제를 어떻게 디버그합니까?Apr 25, 2025 am 12:12 AM

PHP에서 세션 문제를 디버그하는 방법 : 1. 세션이 올바르게 시작되었는지 확인하십시오. 2. 세션 ID의 전달을 확인하십시오. 3. 세션 데이터의 저장 및 읽기를 확인하십시오. 4. 서버 구성을 확인하십시오. 세션 ID 및 데이터를 출력, 세션 파일 컨텐츠보기 등을 통해 세션 관련 문제를 효과적으로 진단하고 해결할 수 있습니다.

session_start ()가 여러 번 호출되면 어떻게됩니까?session_start ()가 여러 번 호출되면 어떻게됩니까?Apr 25, 2025 am 12:06 AM

Session_Start ()로 여러 통화를하면 경고 메시지와 가능한 데이터 덮어 쓰기가 발생합니다. 1) PHP는 세션이 시작되었다는 경고를 발행합니다. 2) 세션 데이터의 예상치 못한 덮어 쓰기를 유발할 수 있습니다. 3) Session_status ()를 사용하여 반복 통화를 피하기 위해 세션 상태를 확인하십시오.

PHP에서 세션 수명을 어떻게 구성합니까?PHP에서 세션 수명을 어떻게 구성합니까?Apr 25, 2025 am 12:05 AM

SESSION.GC_MAXLIFETIME 및 SESSION.COOKIE_LIFETIME을 설정하여 PHP에서 세션 수명을 구성 할 수 있습니다. 1) SESSION.GC_MAXLIFETIME 서버 측 세션 데이터의 생존 시간을 제어합니다. 2) 세션 .Cookie_Lifetime 클라이언트 쿠키의 수명주기를 제어합니다. 0으로 설정하면 브라우저가 닫히면 쿠키가 만료됩니다.

세션을 저장하기 위해 데이터베이스를 사용하면 어떤 장점이 있습니까?세션을 저장하기 위해 데이터베이스를 사용하면 어떤 장점이 있습니까?Apr 24, 2025 am 12:16 AM

데이터베이스 스토리지 세션 사용의 주요 장점에는 지속성, 확장 성 및 보안이 포함됩니다. 1. 지속성 : 서버가 다시 시작 되더라도 세션 데이터는 변경되지 않아도됩니다. 2. 확장 성 : 분산 시스템에 적용하여 세션 데이터가 여러 서버간에 동기화되도록합니다. 3. 보안 : 데이터베이스는 민감한 정보를 보호하기 위해 암호화 된 스토리지를 제공합니다.

PHP에서 사용자 정의 세션 처리를 어떻게 구현합니까?PHP에서 사용자 정의 세션 처리를 어떻게 구현합니까?Apr 24, 2025 am 12:16 AM

SessionHandlerInterface 인터페이스를 구현하여 PHP에서 사용자 정의 세션 처리 구현을 수행 할 수 있습니다. 특정 단계에는 다음이 포함됩니다. 1) CustomsessionHandler와 같은 SessionHandlerInterface를 구현하는 클래스 만들기; 2) 인터페이스의 방법 (예 : Open, Close, Read, Write, Despare, GC)의 수명주기 및 세션 데이터의 저장 방법을 정의하기 위해 방법을 다시 작성합니다. 3) PHP 스크립트에 사용자 정의 세션 프로세서를 등록하고 세션을 시작하십시오. 이를 통해 MySQL 및 Redis와 같은 미디어에 데이터를 저장하여 성능, 보안 및 확장 성을 향상시킬 수 있습니다.

세션 ID 란 무엇입니까?세션 ID 란 무엇입니까?Apr 24, 2025 am 12:13 AM

SessionId는 웹 애플리케이션에 사용되는 메커니즘으로 사용자 세션 상태를 추적합니다. 1. 사용자와 서버 간의 여러 상호 작용 중에 사용자의 신원 정보를 유지하는 데 사용되는 무작위로 생성 된 문자열입니다. 2. 서버는 쿠키 또는 URL 매개 변수를 통해 클라이언트로 생성하여 보낸다. 3. 생성은 일반적으로 임의의 알고리즘을 사용하여 독창성과 예측 불가능 성을 보장합니다. 4. 실제 개발에서 Redis와 같은 메모리 내 데이터베이스를 사용하여 세션 데이터를 저장하여 성능 및 보안을 향상시킬 수 있습니다.

무국적 환경 (예 : API)에서 세션을 어떻게 처리합니까?무국적 환경 (예 : API)에서 세션을 어떻게 처리합니까?Apr 24, 2025 am 12:12 AM

JWT 또는 쿠키를 사용하여 API와 같은 무국적 환경에서 세션을 관리 할 수 ​​있습니다. 1. JWT는 무국적자 및 확장 성에 적합하지만 빅 데이터와 관련하여 크기가 크다. 2. 쿠키는보다 전통적이고 구현하기 쉽지만 보안을 보장하기 위해주의해서 구성해야합니다.

See all articles

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

Video Face Swap

Video Face Swap

완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

뜨거운 도구

mPDF

mPDF

mPDF는 UTF-8로 인코딩된 HTML에서 PDF 파일을 생성할 수 있는 PHP 라이브러리입니다. 원저자인 Ian Back은 자신의 웹 사이트에서 "즉시" PDF 파일을 출력하고 다양한 언어를 처리하기 위해 mPDF를 작성했습니다. HTML2FPDF와 같은 원본 스크립트보다 유니코드 글꼴을 사용할 때 속도가 느리고 더 큰 파일을 생성하지만 CSS 스타일 등을 지원하고 많은 개선 사항이 있습니다. RTL(아랍어, 히브리어), CJK(중국어, 일본어, 한국어)를 포함한 거의 모든 언어를 지원합니다. 중첩된 블록 수준 요소(예: P, DIV)를 지원합니다.

VSCode Windows 64비트 다운로드

VSCode Windows 64비트 다운로드

Microsoft에서 출시한 강력한 무료 IDE 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

ZendStudio 13.5.1 맥

ZendStudio 13.5.1 맥

강력한 PHP 통합 개발 환경