摘要:但是模型中數(shù)據(jù)的變化一般會(huì)通過一種刷新機(jī)制被公布。它處理事件并作出響應(yīng)。事件包括用戶的行為和數(shù)據(jù)模型上的改變。三開始開發(fā)自己的框架在開始開發(fā)前,讓我們先來把項(xiàng)目建立好,假設(shè)我們建立的項(xiàng)目為,那么接下來的第一步就是把目錄結(jié)構(gòu)先設(shè)置好。
一、什么是MVC現(xiàn)如今市面上有許多PHP框架,像 ThinkPHP、YII、Laravel,那么如何自己搭建一個(gè)PHP框架呢?這里有一篇博文寫的非常好,特意轉(zhuǎn)載過來,供朋友們研究,原文請(qǐng)戳詳情。
MVC 模式(Model-View-Controller)是軟件工程中的一種軟件架構(gòu)模式,把軟件系統(tǒng)分為三個(gè)基本部分:模型(Model)、視圖(View)和控制器(Controller)。
MVC 模式的目的是實(shí)現(xiàn)一種動(dòng)態(tài)的程序設(shè)計(jì),使后續(xù)對(duì)程序的修改和擴(kuò)展簡化,并且使程序某一部分的重復(fù)利用成為可能。除此之外,此模式通過對(duì)復(fù)雜度的簡化,使程序結(jié)構(gòu)更加直觀。軟件系統(tǒng)通過對(duì)自身基本部份分離的同時(shí)也賦予了各個(gè)基本部分應(yīng)有的功能。專業(yè)人員可以通過自身的專長分組:
(控制器Controller)- 負(fù)責(zé)轉(zhuǎn)發(fā)請(qǐng)求,對(duì)請(qǐng)求進(jìn)行處理。
(視圖View) – 界面設(shè)計(jì)人員進(jìn)行圖形界面設(shè)計(jì)。
(模型Model) – 程序員編寫程序應(yīng)有的功能(實(shí)現(xiàn)算法等等)、數(shù)據(jù)庫專家進(jìn)行數(shù)據(jù)管理和數(shù)據(jù)庫設(shè)計(jì)(可以實(shí)現(xiàn)具體的功能)。
模型(Model): “數(shù)據(jù)模型”(Model)用于封裝與應(yīng)用程序的業(yè)務(wù)邏輯相關(guān)的數(shù)據(jù)以及對(duì)數(shù)據(jù)的處理方法。“模型”有對(duì)數(shù)據(jù)直接訪問的權(quán)力,例如對(duì)數(shù)據(jù)庫的訪問?!澳P汀辈灰蕾嚒耙晥D”和“控制器”,也就是說,模型不關(guān)心它會(huì)被如何顯示或是如何被操作。但是模型中數(shù)據(jù)的變化一般會(huì)通過一種刷新機(jī)制被公布。為了實(shí)現(xiàn)這種機(jī)制,那些用于監(jiān)視此模型的視圖必須事先在此模型上注冊(cè),從而,視圖可以了解在數(shù)據(jù)模型上發(fā)生的改變。
視圖(View): 視圖層能夠?qū)崿F(xiàn)數(shù)據(jù)有目的的顯示(理論上,這不是必需的)。在視圖中一般沒有程序上的邏輯。為了實(shí)現(xiàn)視圖上的刷新功能,視圖需要訪問它監(jiān)視的數(shù)據(jù)模型(Model),因此應(yīng)該事先在被它監(jiān)視的數(shù)據(jù)那里注冊(cè)。
控制器(Controller): 控制器起到不同層面間的組織作用,用于控制應(yīng)用程序的流程。它處理事件并作出響應(yīng)?!笆录卑ㄓ脩舻男袨楹蛿?shù)據(jù)模型上的改變。
二、為什么要自己開發(fā)MVC框架網(wǎng)絡(luò)上有大量優(yōu)秀的 MVC 框架可供使用,本教程并不是為了開發(fā)一個(gè)全面的、終極的 MVC 框架解決方案,而是將它看作是一個(gè)很好的從內(nèi)部學(xué)習(xí) PHP 的機(jī)會(huì),在此過程中,你將學(xué)習(xí)面向?qū)ο缶幊毯驮O(shè)計(jì)模式,并學(xué)習(xí)到開放中的一些注意事項(xiàng)。
更重要的是,你可以完全控制你的框架,并將你的想法融入到你開發(fā)的框架中。雖然不一定是做好的,但是你可以按照你的方式去開發(fā)功能和模塊。
三、開始開發(fā)自己的MVC框架在開始開發(fā)前,讓我們先來把項(xiàng)目建立好,假設(shè)我們建立的項(xiàng)目為 Frame,那么接下來的第一步就是把目錄結(jié)構(gòu)先設(shè)置好。
雖然在這個(gè)教程中不會(huì)使用到上面的所有的目錄,但是為了以后程序的可拓展性,在一開始就把程序目錄設(shè)置好使非常必要的。下面就具體說說每個(gè)目錄的作用:
application – 存放程序代碼
config – 存放程序配置或數(shù)據(jù)庫配置
db – 用來存放數(shù)據(jù)庫備份內(nèi)容
library – 存放框架代碼
public – 存放靜態(tài)文件
scripts – 存放命令行工具
tmp – 存放臨時(shí)數(shù)據(jù)
在目錄設(shè)置好以后,我們接下來就要來頂一下一些代碼的規(guī)范:
MySQL的表名需小寫并采用復(fù)數(shù)形式,如items,cars
模塊名(Models)需首字母大寫,并采用單數(shù)模式,如Item,Car
控制器(Controllers)需首字母大寫,采用復(fù)數(shù)形式并在名稱中添加“Controller”,如 ItemsController, CarsController
視圖(Views)采用復(fù)數(shù)形式,并在后面添加行為作為文件,如:items/view.php, cars/buy.php
上述的一些規(guī)則是為了能在程序鐘更好的進(jìn)行互相的調(diào)用。接下來就開始真正的編碼了。
第一步將所有的的請(qǐng)求都重定向到 public 目錄下,解決方案是在 Frame 文件下添加一個(gè).htaccesss文件,文件內(nèi)容為:
RewriteEngine on RewriteRule ^$ public/ [L] RewriteRule (.*) public/$1 [L]
在我們把所有的請(qǐng)求都重定向到 public 目錄下以后,我們就需要將所有的數(shù)據(jù)請(qǐng)求都再重定向到 public 下的 index.php 文件,于是就需要在public文件夾下也新建一個(gè).htaccess文件,文件內(nèi)容為:
RewriteEngine On #如果文件存在就直接訪問目錄不進(jìn)行RewriteRule RewriteCond %{REQUEST_FILENAME} !-f #如果目錄存在就直接訪問目錄不進(jìn)行RewriteRule RewriteCond %{REQUEST_FILENAME} !-d #將所有其他URL重寫到 index.php/URL RewriteRule ^(.*)$ index.php?url=$1 [PT,L]
這么做的主要原因有:
可以使程序有一個(gè)單一的入口,將所有除靜態(tài)程序以外的程序都重定向到index.php上;
可以用來生成利于SEO的URL,想要更好的配置URL,后期可能會(huì)需要URL路由,這里先不做介紹了。
做完上面的操作,就應(yīng)該知道我們需要做什么了,沒錯(cuò)!在public目錄下添加 index.php 文件,文件內(nèi)容為:
注意上面的PHP代碼中,并沒有添加PHP結(jié)束符號(hào)”?>”,這么做的主要原因是:對(duì)于只包含PHP代碼的文件,結(jié)束標(biāo)志(“?>”)最好不存在,PHP自身并不需要結(jié)束符號(hào),不添加結(jié)束符號(hào)可以很大程度上防止末尾被添加額外的注入內(nèi)容,讓程序更加安全。
在index.php中,我們對(duì) library 文件夾下的 bootstrap.php 發(fā)起了請(qǐng)求,那么bootstrap.php 這個(gè)啟動(dòng)文件中到底會(huì)包含哪些內(nèi)容呢?
以上文件都可以直接在index.php文件中引用,我們這么做的原因是為了在后期管理和拓展中更加的方便,所以把需要在一開始的時(shí)候就加載運(yùn)行的程序統(tǒng)一放到一個(gè)多帶帶的文件中引用。
先來看看config文件下的 config .php 文件,該文件的主要作用是設(shè)置一些程序的配置項(xiàng)及數(shù)據(jù)庫連接等,主要內(nèi)容為:
應(yīng)該說config.php涉及到的內(nèi)容并不多,不過是一些基礎(chǔ)數(shù)據(jù)的一些設(shè)置,再來看看library下的共用文件 shared.php 應(yīng)該怎么寫。
的method屬性為post的時(shí)候應(yīng)該用$_POST["user_name"]和$_POST["user_pass"]) * 當(dāng)register_globals=On的時(shí)候,下一個(gè)程序可以直接使用$user_name和$user_pass來接受值。 * 顧名思義,register_globals的意思就是注冊(cè)為全局變量,所以當(dāng)On的時(shí)候,傳遞過來的值會(huì)被直接的注冊(cè)為全局變量直接使用,而Off的 * 時(shí)候,我們需要到特定的數(shù)組里去得到它。所以,碰到上邊那些無法得到值的問題的朋友應(yīng)該首先檢查一下你的register_globals的設(shè)置和 * 你獲取值的方法是否匹配。 * * 那我們?yōu)槭裁匆褂肙ff呢? * 原因有2: * 1、php以后的新版本默認(rèn)都用Off,雖然你可以設(shè)置它為On,但是當(dāng)你無法控制服務(wù)器的時(shí)候,你的代碼的兼容性就成為一個(gè)大問題,所以 *,你最好從現(xiàn)在就開始用Off的風(fēng)格開始編程 2、這里有兩篇文章介紹為什么要Off而不用On */ function unregisterGlobals() { if(ini_get("register_globals")) { $array = array("_SESSION","_POST","_GET","_COOKIE","_REQUEST","_SERVER","_ENV","_FILES"); foreach ($array as $value) { // $GLOBALS 可以打印所有的全局變量 foreach ($GLOBALS[$value] as $key => $var) { if ($var === $GLOBALS[$key]) { unset($GLOBALS[$key]); } } } } } /** * 請(qǐng)求方法,主要目的拆分URL請(qǐng)求 * * 相關(guān)學(xué)習(xí): * 調(diào)用回調(diào)函數(shù),并把一個(gè)數(shù)組參數(shù)作為回調(diào)函數(shù)的參數(shù) * call_user_func_array(array($obj, $method_name), $params); * call_user_method_array ( string $method_name , object &$obj , array $params ) */ function callHook() { global $url; $urlArray = array(); $urlArray = explode("/", $url); // 獲取控制器 controller $controller = $urlArray[0]; // 刪除第一個(gè)元素 array_shift($urlArray); // 獲取動(dòng)作 Action $action = $urlArray[0]; array_shift($urlArray); $queryString = $urlArray; $controllerName = $controller; $controller = ucwords($controller); $model = rtrim($controller, "s"); $controller .= "Controller"; $dispatch = new $controller($model, $controllerName, $action); if((int)method_exists($controller, $action)) // 檢查類的方法是否存在(可以傳遞類名或?qū)ο竺? { call_user_func_array(array($dispatch, $action), $queryString); } else { /* 生成錯(cuò)誤代碼 */ exit("該控制器不存在:". $controller); } } /** * 自動(dòng)加載控制器和模型 */ function __autoload($className) { if(file_exists(ROOT . DS . "library" . DS . strtolower($className) . ".class.php")) { // 加載核心庫 library require_once(ROOT . DS . "library" . DS . strtolower($className) . ".class.php"); } else if(file_exists(ROOT . DS . "application" . DS . "controllers" . DS . strtolower($className) . ".php")) { // 加載控制器 application 目錄下 require_once(ROOT . DS . "application" . DS . "controllers" . DS . strtolower($className) . ".php"); } else if(file_exists(ROOT . DS . "application" . DS . "models" . DS . strtolower($className) . ".php")) { // 加載控制器 application 目錄下 require_once(ROOT . DS . "application" . DS . "models" . DS . strtolower($className) . ".php"); } else { /* 生成錯(cuò)誤代碼 */ exit("類名不存在:" . $className); } } setReporting(); removeMagicQuotes(); unregisterGlobals(); callHook();接下來的操作就是在library中建立程序所需要的基類,包括控制器、模型和視圖的基類。
新建控制器基類為controller.class.php,控制器的主要功能就是總調(diào)度,具體具體內(nèi)容如下:
_controller = $controller; $this->_action = $action; $this->_model = $model; $this->$model =& new $model; // php默認(rèn)為傳值傳遞,這里默認(rèn)為地址傳遞,即引用同一個(gè)對(duì)象 $this->_template =& new Template($controller, $action); } function set($name,$value) { $this->_template->set($name,$value); } function __destruct() { // 放在析構(gòu)函數(shù)中是為了在釋放實(shí)例化的時(shí)候執(zhí)行下面的方法 $this->_template->render(); } }新建控制器基類為 model.class.php,考慮到模型需要對(duì)數(shù)據(jù)庫進(jìn)行處理,所以可以新建一個(gè)數(shù)據(jù)庫基類 sqlquery.class.php,模型去繼承 sqlquery.class.php。
新建 sqlquery.class.php,代碼如下:
_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; } } /** 中斷數(shù)據(jù)庫連接 **/ function disconnect() { if (@mysql_close($this->_dbHandle) != 0) { return 1; } else { return 0; } } /** 查詢所有數(shù)據(jù)表內(nèi)容 **/ function selectAll() { $query = "select * from `".$this->_table."`"; return $this->query($query); } /** 查詢數(shù)據(jù)表指定列內(nèi)容 **/ function select($id) { $query = "select * from `".$this->_table."` where `id` = "".mysql_real_escape_string($id)."""; return $this->query($query, 1); } /** 自定義SQL查詢語句 **/ 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] = trim(ucfirst($table[$i]),"s"); $tempResults[$table[$i]][$field[$i]] = $row[$i]; } if ($singleResult == 1) { mysql_free_result($this->_result); return $tempResults; } array_push($result,$tempResults); } mysql_free_result($this->_result); return($result); } } /** 返回結(jié)果集行數(shù) **/ function getNumRows() { return mysql_num_rows($this->_result); } /** 釋放結(jié)果集內(nèi)存 **/ function freeResult() { mysql_free_result($this->_result); } /** 返回MySQL操作錯(cuò)誤信息 **/ function getError() { return mysql_error($this->_dbHandle); } }新建 model.class.php,代碼如下:
connect(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME); $this->_model = get_class($this); $this->_table = strtolower($this->_model)."s"; } function __destruct() { } }新建視圖基類為template.class.php,具體代碼如下:
_controller = $controller; $this->_action =$action; } /* 設(shè)置變量 */ function set($name,$value) { $this->variables[$name] = $value; } /* 顯示模板 */ function render() { extract($this->variables); if (file_exists(ROOT.DS. "application" .DS. "views" .DS. $this->_controller .DS. "header.php")) { include(ROOT.DS. "application" .DS. "views" .DS. $this->_controller .DS. "header.php"); } else { include(ROOT.DS. "application" .DS. "views" .DS. "header.php"); } include (ROOT.DS. "application" .DS. "views" .DS. $this->_controller .DS. $this->_action . ".php"); if (file_exists(ROOT.DS. "application" .DS. "views" .DS. $this->_controller .DS. "footer.php")) { include (ROOT.DS. "application" .DS. "views" .DS. $this->_controller .DS. "footer.php"); } else { include (ROOT.DS. "application" .DS. "views" .DS. "footer.php"); } } }四、框架應(yīng)用做完了以上這么多操作,基本上整個(gè)MVC框架已經(jīng)出來了,下面就該制作我們的站點(diǎn)了。我們要做的站點(diǎn)其實(shí)很簡單,一個(gè)ToDo程序。
首先是在我們的 /application/controller/ 目錄下面新建一個(gè)站點(diǎn)控制器類為ItemsController,命名為itemscontroller.php,內(nèi)容為:
set("title",$name." - My Todo List App"); $this->set("todo",$this->Item->select($id)); } function viewall() { $this->set("title","All Items - My Todo List App"); $this->set("todo",$this->Item->selectAll()); } function add() { $todo = $_POST["todo"]; $this->set("title","Success - My Todo List App"); $this->set("todo",$this->Item->query("insert into items (item_name) values ("".mysql_real_escape_string($todo)."")")); } function delete($id) { $this->set("title","Success - My Todo List App"); $this->set("todo",$this->Item->query("delete from items where id = "".mysql_real_escape_string($id).""")); } }接下來就是先建站點(diǎn)的模型,在我們的/application/model/ 目錄下面先建一個(gè)站點(diǎn)模型類為Item,內(nèi)容直接繼承Model,代碼如下:
最后一步是設(shè)置我們站點(diǎn)的視圖部分,我們現(xiàn)在/application/views/目錄下新建一個(gè)items的文件夾,再在items文件夾下建立與控制器重Action相同的文件,分別為view.php,viewall.php,add.php,delete.php,考慮到這么頁面中可能需要共用頁首和頁尾,所以再新建兩個(gè)文件,命名為header.php,footer.php,每個(gè)文件的代碼如下:
view.php文件:查看單條待處理事務(wù)
"> Delete this itemviewall.php文件:查看所有待處理事務(wù)
add.php文件:添加待處理事務(wù)
Todo successfully added. Click here to go back.
delete.php文件:刪除事務(wù)
Todo successfully deleted. Click here to go back.
header.php:頁首文件
My Todo-List App
footer.php:頁尾文件
當(dāng)然還有一個(gè)必不可少的操作就是在數(shù)據(jù)中中建立一張表,具體代碼如下:
CREATE TABLE IF NOT EXISTS `items` ( `id` int(11) NOT NULL AUTO_INCREMENT, `item_name` varchar(255) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=17 ;
至此一個(gè)使用MVC開發(fā)的網(wǎng)站就開發(fā)完成了,你現(xiàn)在可以通過訪問http://localhost/Frame/items/... 查看新建的站點(diǎn)。
框架核心小結(jié):
1、單一入口原則
在項(xiàng)目Frame 下寫.htaccess 文件指定到 pulibc 目錄, 然后在 public 目錄下重寫入口模塊 .htaccess 指定到 index.php 文件
這樣只要訪問該項(xiàng)目,就會(huì)指定到 Frame/public/index.php 目錄下
2、加載初始配置文件
定義根路徑,分隔符,等常量
define("DEBUG", TRUE);
3、封裝核心類
sql.php
model.php (該類繼承sql.php)
controller.php
4、其他的類都繼承核心類
注:本文為轉(zhuǎn)載,原文地址:請(qǐng)戳這里
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/23045.html
摘要:菜鳥教程框架中文手冊(cè)入門目標(biāo)使用搭建通過對(duì)數(shù)據(jù)增刪查改沒了純粹占行用的拜 后端API入門學(xué)習(xí)指北 了解一下一下概念. RESTful API標(biāo)準(zhǔn)] 所有的API都遵循[RESTful API標(biāo)準(zhǔn)]. 建議大家都簡單了解一下HTTP協(xié)議和RESTful API相關(guān)資料. 阮一峰:理解RESTful架構(gòu) 阮一峰:RESTful API 設(shè)計(jì)指南 RESTful API指南 依賴注入 D...
摘要:菜鳥教程框架中文手冊(cè)入門目標(biāo)使用搭建通過對(duì)數(shù)據(jù)增刪查改沒了純粹占行用的拜 后端API入門學(xué)習(xí)指北 了解一下一下概念. RESTful API標(biāo)準(zhǔn)] 所有的API都遵循[RESTful API標(biāo)準(zhǔn)]. 建議大家都簡單了解一下HTTP協(xié)議和RESTful API相關(guān)資料. 阮一峰:理解RESTful架構(gòu) 阮一峰:RESTful API 設(shè)計(jì)指南 RESTful API指南 依賴注入 D...
摘要:菜鳥教程框架中文手冊(cè)入門目標(biāo)使用搭建通過對(duì)數(shù)據(jù)增刪查改沒了純粹占行用的拜 后端API入門學(xué)習(xí)指北 了解一下一下概念. RESTful API標(biāo)準(zhǔn)] 所有的API都遵循[RESTful API標(biāo)準(zhǔn)]. 建議大家都簡單了解一下HTTP協(xié)議和RESTful API相關(guān)資料. 阮一峰:理解RESTful架構(gòu) 阮一峰:RESTful API 設(shè)計(jì)指南 RESTful API指南 依賴注入 D...
摘要:不是原創(chuàng)的,主要是看了覺得有些幫助,就分享給大家看看。對(duì)于的知識(shí)要求我覺得以鳥哥的私房菜這本書作為要求吧。前端大部分使用,對(duì)靜態(tài)資源使用可以加載更快。其實(shí)編程使用什么語言不重要,最重要的是思想,編程的思路。 不是原創(chuàng)的,主要是看了覺得有些幫助,就分享給大家看看。 PHP的運(yùn)行環(huán)境 連環(huán)境都搞不起來,就是你有多么喜歡PHP,那也是白搭,開始我們大多會(huì)使用集成環(huán)境軟件例如xampp,wam...
摘要:今天我在這里給大家分享一下在中如何創(chuàng)建數(shù)據(jù)模型和基于的搭建。對(duì)象與數(shù)據(jù)庫的關(guān)系通常在電腦的世界里創(chuàng)建的數(shù)據(jù)模型會(huì)轉(zhuǎn)換為數(shù)據(jù)庫里的一條條記錄。 Symfony是一款優(yōu)秀的基于MVC架構(gòu)的PHP框架。今天我在這里給大家分享一下在Symfony中如何創(chuàng)建數(shù)據(jù)模型和基于RESTful api的搭建。重點(diǎn)是如何創(chuàng)建數(shù)據(jù)模型哦! 本教程使用的當(dāng)前Symfony的LTS版本(Symfony 2.8...
閱讀 3515·2021-11-22 12:00
閱讀 746·2019-08-29 13:24
閱讀 2966·2019-08-29 11:31
閱讀 2675·2019-08-26 14:00
閱讀 3266·2019-08-26 11:42
閱讀 2535·2019-08-23 18:31
閱讀 865·2019-08-23 18:27
閱讀 2905·2019-08-23 16:58