开发自己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框架(二)》

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

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

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

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

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

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

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

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


핫 AI 도구

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

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

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

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

인기 기사

뜨거운 도구

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

VSCode Windows 64비트 다운로드
Microsoft에서 출시한 강력한 무료 IDE 편집기

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

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

ZendStudio 13.5.1 맥
강력한 PHP 통합 개발 환경
