开发自各儿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."
<?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
//当类初始化时,自动引入相关文件 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."); } }
保存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; } }?>
public function main(array $getVars) { $newsModel = new News_Model; //获取一篇文章 $article = $newsModel->get_article('test'); print_r($article); }
如果访问如下网址:
§ 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框架(二)》

핫 AI 도구

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

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

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

Clothoff.io
AI 옷 제거제

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

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

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

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

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











PHP 8.4는 상당한 양의 기능 중단 및 제거를 통해 몇 가지 새로운 기능, 보안 개선 및 성능 개선을 제공합니다. 이 가이드에서는 Ubuntu, Debian 또는 해당 파생 제품에서 PHP 8.4를 설치하거나 PHP 8.4로 업그레이드하는 방법을 설명합니다.

숙련된 PHP 개발자라면 이미 그런 일을 해왔다는 느낌을 받을 것입니다. 귀하는 상당한 수의 애플리케이션을 개발하고, 수백만 줄의 코드를 디버깅하고, 여러 스크립트를 수정하여 작업을 수행했습니다.

VS Code라고도 알려진 Visual Studio Code는 모든 주요 운영 체제에서 사용할 수 있는 무료 소스 코드 편집기 또는 통합 개발 환경(IDE)입니다. 다양한 프로그래밍 언어에 대한 대규모 확장 모음을 통해 VS Code는

JWT는 주로 신분증 인증 및 정보 교환을 위해 당사자간에 정보를 안전하게 전송하는 데 사용되는 JSON을 기반으로 한 개방형 표준입니다. 1. JWT는 헤더, 페이로드 및 서명의 세 부분으로 구성됩니다. 2. JWT의 작업 원칙에는 세 가지 단계가 포함됩니다. JWT 생성, JWT 확인 및 Parsing Payload. 3. PHP에서 인증에 JWT를 사용하면 JWT를 생성하고 확인할 수 있으며 사용자 역할 및 권한 정보가 고급 사용에 포함될 수 있습니다. 4. 일반적인 오류에는 서명 검증 실패, 토큰 만료 및 대형 페이로드가 포함됩니다. 디버깅 기술에는 디버깅 도구 및 로깅 사용이 포함됩니다. 5. 성능 최적화 및 모범 사례에는 적절한 시그니처 알고리즘 사용, 타당성 기간 설정 합리적,

이 튜토리얼은 PHP를 사용하여 XML 문서를 효율적으로 처리하는 방법을 보여줍니다. XML (Extensible Markup Language)은 인간의 가독성과 기계 구문 분석을 위해 설계된 다목적 텍스트 기반 마크 업 언어입니다. 일반적으로 데이터 저장 AN에 사용됩니다

문자열은 문자, 숫자 및 기호를 포함하여 일련의 문자입니다. 이 튜토리얼은 다른 방법을 사용하여 PHP의 주어진 문자열의 모음 수를 계산하는 방법을 배웁니다. 영어의 모음은 A, E, I, O, U이며 대문자 또는 소문자 일 수 있습니다. 모음이란 무엇입니까? 모음은 특정 발음을 나타내는 알파벳 문자입니다. 대문자와 소문자를 포함하여 영어에는 5 개의 모음이 있습니다. a, e, i, o, u 예 1 입력 : String = "Tutorialspoint" 출력 : 6 설명하다 문자열의 "Tutorialspoint"의 모음은 u, o, i, a, o, i입니다. 총 6 개의 위안이 있습니다

정적 바인딩 (정적 : :)는 PHP에서 늦은 정적 바인딩 (LSB)을 구현하여 클래스를 정의하는 대신 정적 컨텍스트에서 호출 클래스를 참조 할 수 있습니다. 1) 구문 분석 프로세스는 런타임에 수행됩니다. 2) 상속 관계에서 통화 클래스를 찾아보십시오. 3) 성능 오버 헤드를 가져올 수 있습니다.

PHP의 마법 방법은 무엇입니까? PHP의 마법 방법은 다음과 같습니다. 1. \ _ \ _ Construct, 객체를 초기화하는 데 사용됩니다. 2. \ _ \ _ 파괴, 자원을 정리하는 데 사용됩니다. 3. \ _ \ _ 호출, 존재하지 않는 메소드 호출을 처리하십시오. 4. \ _ \ _ get, 동적 속성 액세스를 구현하십시오. 5. \ _ \ _ Set, 동적 속성 설정을 구현하십시오. 이러한 방법은 특정 상황에서 자동으로 호출되어 코드 유연성과 효율성을 향상시킵니다.
