標籤:php mvc ie6 架構 設計模式
MVC只是一種設計模式而已,一度被認為Model 1,也就是伺服器語句與HTML語句雜糅的php,其實不用任何架構,僅僅利用原生態的JavaScript Ajax也可以對其進行MVC設計。由於什麼都沒有用,因此對IE6的相容性是非常強的。還是《【php】資料庫的增刪改查和php與javascript之間的互動》(點擊開啟連結)那個頁面的,對資料庫增刪改查的內容,希望各位能推廣到整個網站。
一、基本目標
整個網頁實現效果如下,使用者輸入完表單馬上就有效果。
二、基本思想
首先,在test資料庫中有一張這樣的使用者資訊表,建表的時候注意檢查一下那些資料庫欄位的編碼是否是utf-8,一些Mysql在安裝時候沒有改預設的編碼latin1的,不然一會兒你打死無法存中文。
然後,整個網頁工程結構如:
在view.php中網頁中不進行任何重新整理,利用原生態的JavaScript Ajax,直接完成V-C層的互動。C-M層的互動通過include語句,引入M層的商務邏輯類中方法,通過類參數的傳遞完成。
同時,C、M層的php拒絕直接輸入網址訪問。這裡不像JSP或者ASP,C層、M層都是編譯之後的JAVA檔案或者C#檔案,根本就訪問不了。我們還要對其進行保護。
三、製作過程
1、View層就一個簡單的View.php,其布局如下,沒什麼好說的,非常簡單的HTML布局。同時,注意,本頁面:
(1)沒有設定表單,所有表單提交的動作,通過button觸發相應的JavaScript而觸發。
(2)各個組件的ID,一會兒在JavaScript用到。其中使用者資訊表、修改ID的下拉框都是通過下面的指令碼Ajax而載入的。
(3)布局中,包括一會兒的指令碼在內沒有任何php代碼,便於各位布局。你把尾碼名改成.html也能夠正常運行。什麼叫做真正的View層?這就是了,沒有任何的伺服器代碼。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>使用者資訊表</title></head><body>使用者資訊表如下:<div id="result"></div><hr />插入資料<br />使用者名稱:<input type="text" name="username" />密碼:<input type="text" name="password" /><button onclick="insert()">GO!</button><hr />修改資料<br /><select id="userid" name="userid"></select><select name="rowname"> <option value="username">使用者名稱</option> <option value="password">密碼</option></select><input type="text" name="rowtext" /><button onclick="update()">GO!</button></body></html>
其實整個View層的精髓在於下面的JavaScript指令碼。View層就無須使用到Xajax這個外掛程式了,《【php】Xajax Helloworld》(點擊開啟連結)。直接用原生態的JavaScript寫。雖然代碼量比起JQuery等前端架構較多,記住不容易。從建立Ajax對象,設定Ajax要求標頭,處理Ajax文本都要自己寫,但在開發過程中,只是複製粘貼而已。因此可以觀察到,所有的Ajax互動函數都大同小易。拿ForAllUserInfo();這個函數來重點說明怎麼V-C層怎麼通過Ajax互動。
<script>//首先,本頁面一載入就調用兩個函數,載入本頁。ForAllUserInfo();ForTotal();//建立Ajax對象,不同瀏覽器有不同的建立方法,其實本函數就是一個簡單的new語句而已。function createXMLHttpRequest(XMLHttpRequest){var XMLHttpRequest;if(window.XMLHttpRequest){XMLHttpRequest=new XMLHttpRequest();}else if(window.ActiveXObject){try{XMLHttpRequest=new ActiveXObject("Msxml2.XMLHTTP");}catch(e){XMLHttpRequest=new ActiveXObject("Microsoft.XMLHTTP");}}return XMLHttpRequest;}function ForAllUserInfo(){var XMLHttpRequest=createXMLHttpRequest(XMLHttpRequest);//指明相應頁面var url="dbselect.php";XMLHttpRequest.open("POST",url,true);//這裡沒法解釋,你所有JavaScript的要求標頭都這樣寫就對了,不會亂碼XMLHttpRequest.setRequestHeader("Content-Type","application/x-www-form-urlencoded");//對於dbselect.php,本view.php沒有任何參數給你。XMLHttpRequest.send(null);//對於返回結果怎麼處理的問題XMLHttpRequest.onreadystatechange=function(){//這個4代表已經發送完畢之後if(XMLHttpRequest.readyState==4){//200代表正確收到了返回結果if(XMLHttpRequest.status==200){//那麼id為result的div,就是整個dbselect.php頁面了。document.getElementById("result").innerHTML=XMLHttpRequest.responseText;}else{//如果不能正常接受結果,你肯定是斷網,或者我的伺服器關掉了。alert("網路連接中斷!");}}};}function ForTotal(){var XMLHttpRequest=createXMLHttpRequest(XMLHttpRequest);var url="dbtotal.php";XMLHttpRequest.open("POST",url,true);XMLHttpRequest.setRequestHeader("Content-Type","application/x-www-form-urlencoded");XMLHttpRequest.send(null);XMLHttpRequest.onreadystatechange=function(){if(XMLHttpRequest.readyState==4){if(XMLHttpRequest.status==200){var total=parseInt(XMLHttpRequest.responseText);//先把修改ID的下拉式清單清空document.getElementById("userid").innerHTML="";if(total>0){for(var i=1;i<total+1;i++){//javascript增加節點過程,資料庫有多少項就填充多少個ID給使用者修改。var selectnode=document.createElement("option");selectnode.value=i;selectnode.innerHTML=i;document.getElementById("userid").appendChild(selectnode);}}}else{alert("網路連接中斷!");}}};}function insert(){//從輸入框拿來插入資料的所有表單var username=document.getElementById("username").value;var password=document.getElementById("password").value;//如果使用者輸入的值不為空白,則執行Ajaxif(username!=""&&password!=""){var XMLHttpRequest=createXMLHttpRequest(XMLHttpRequest);var url="dbinsert.php";XMLHttpRequest.open("POST",url,true);XMLHttpRequest.setRequestHeader("Content-Type","application/x-www-form-urlencoded");//這裡View層的View.php需要發送兩個參數給Controll層的dbinsert.php處理XMLHttpRequest.send("username="+username+"&password="+password);XMLHttpRequest.onreadystatechange=function(){if(XMLHttpRequest.readyState==4){if(XMLHttpRequest.status==200){//添加資料成功,則部分重新整理View層的使用者資訊表與修改ID的下拉式清單ForAllUserInfo();ForTotal();}else{alert("網路連接中斷!");}}};}else{alert("不得為空白!");}}//這裡修改資料與insert()同理function update(){var userid=document.getElementById("userid").value;var rowname=document.getElementById("rowname").value;var rowtext=document.getElementById("rowtext").value;if(userid!=""&&rowname!=""&&rowtext!=""){var XMLHttpRequest=createXMLHttpRequest(XMLHttpRequest);var url="dbupdate.php";XMLHttpRequest.open("POST",url,true);XMLHttpRequest.setRequestHeader("Content-Type","application/x-www-form-urlencoded");XMLHttpRequest.send("userid="+userid+"&rowname="+rowname+"&rowtext="+rowtext);XMLHttpRequest.onreadystatechange=function(){if(XMLHttpRequest.readyState==4){if(XMLHttpRequest.status==200){ForAllUserInfo();ForTotal();}else{alert("網路連接中斷!");}}};}else{alert("不得為空白!");}}</script>
2、Controll層
Controll層的頁面都與View層中的JavaScript函數一一對應。
比如dbupdate.php就對應view.php中的update()函數。通過如下兩句對應起來。
var url="dbupdate.php";XMLHttpRequest.open("POST",url,true);
(1)dbupdate.php
非常簡單的頁面,拿到前端送過來的兩個資料,則進行與Model層的互動,完成資料庫的操作。修改資料庫,資料庫是不會返回任何結果的,因此也沒有什麼資料給前端的。如果拿不到前端送過來的參數,那一定是惡意使用者,通過輸入網址非正常開啟此頁。C層M層一般是不給你開啟的。
<?phpinclude_once("db.php");if(empty($_REQUEST["userid"])){header("Content-type: text/html; charset=utf-8"); echo "請正常開啟此頁!";}else{$db=new db();$userid=$_REQUEST["userid"];$rowname=$_REQUEST["rowname"];$rowtext=$_REQUEST["rowtext"];$db->modify("update user set ".$rowname."='".$rowtext."' where id=".$userid.";");}?>
(2)dbinsert.php
插入資料同樣的道理了,不再贅述。對應於前端的insert()函數
<?phpinclude_once("db.php");if(empty($_REQUEST["username"])){header("Content-type: text/html; charset=utf-8"); echo "請正常開啟此頁!";}else{$db=new db();$username=$_REQUEST["username"];$password=$_REQUEST["password"];$db->modify("insert into user(username,password) values ('".$username."','".$password."');");}?>
(3)dbtotal.php
這一頁是用來查詢資料庫有多少條結果,我們在修改資料的下拉式清單就要提供給使用者多少個ID,給使用者指定修改。
對應於view.php中的ForTotal()函數。這一頁是有返回結果的。因此dbtotal.php就把這個結果用echo列印出來,前端通過:
var total=parseInt(XMLHttpRequest.responseText);
這一句中的XMLHttpRequest.responseText拿到,前端的JavaScript必須強制指明這是數字,否則則出現7+1=71的神運算。JavaScript把數字當字串了,也沒辦法了,畢竟所有變數都是var。php則都是美元$。
這一頁就無須保護了,畢竟肯定要給使用者看的。
<?phpinclude_once("db.php");$db=new db();$total=$db->getTotal();echo $total;?>
(4)dbselect.php
這一頁其實和dbtotal.php一樣,不過變成了構造一個表格,送給前端View.php的ForAllUserInfo()。ForAllUserInfo()得到的資料其實一段HTML文本,直接通過.innerHTML放上去就可以了。
<?phpinclude_once("db.php");$db=new db();$user=$db->getAllUserInfo();?><table border="1"><tr><th>ID</th><th>使用者名稱</th><th>密碼</th></tr><?phpfor($i=0;$i<count($user);$i++){echo "<tr><td>".$user[$i]['id']."</td><td>".$user[$i]['username']."</td><td>".$user[$i]['password']."</td></tr>";}?></table>
這頁有HTML打死都不能與PHP代碼混在一起的強迫症患者,請自行把所有HTML的代碼,給成echo輸出,反正我就只能給出這樣的一個方案了。
3、Model層
這一層的所有方法都與C層的頁面存在對應關係。
首先都公用一個資料庫連接函數。之後各自在方法中調用,最後各自查詢完畢則關閉這個串連。
然後,可以注意到上面的Controll層的dbupdate.php與dbinsert.php公用此類的一個方法。這主要是考慮到,都是傳遞一個SQL語句過來,然後沒有返回結果,因此可以合在一起了。而查詢資料庫的所有資料與查詢資料庫的資料數量的返回結果是不同的,因此分開兩個方法。
<?phpfunction createCon(){//資料庫的地址是localhost:3306,資料庫使用者名稱(第二項)是root,資料庫密碼(第三項)是root$con=mysql_connect("localhost","root","root");if(!$con){die("串連失敗!");}//要操作test資料庫mysql_select_db("test",$con);//防止亂碼mysql_query("set names utf8;");return $con;}class db{public function getAllUserInfo(){$con=createCon();$result=mysql_query("select * from user;");//如果查詢的結果多,就放到一個二維數組裡面,返回給Controll層//Controll層再對這個二維數組一一處理。//起始這個二維數組不就相當於JSP中的ArrayList嗎?^_^$userList=array();for($i=0;$row=mysql_fetch_array($result);$i++){$userList[$i]['id']=$row['id'];$userList[$i]['username']=$row['username'];$userList[$i]['password']=$row['password'];}mysql_close($con);return $userList;}public function getTotal(){$con=createCon();$result=mysql_query("select count(*) as total from user;");//如果返回結果只有一個,那就直接這樣取資料。$row=mysql_fetch_array($result);mysql_close($con);return $row['total'];}public function modify($sql){//對於那些傳sql過來沒有返回結果的方法,歸納到同一類$con=createCon();mysql_query($sql);mysql_close($con);}}?>
四、總結與展望
上面的製作過程最好合在一起看,反正我只能這樣分層貼了。V-C,C-M一直在互動,從未被割裂,根本停不下來。對比與《【php】資料庫的增刪改查和php與javascript之間的互動》(點擊開啟連結)這個以MODEL1模式創作的工程,頁面雖然增多,但是模組更加地清晰。
反正MVC僅僅是一種設計模式、設計思想而已,在PHP同樣也能夠實現。在JSP對這種模式的吹噓是言過其實了,主要是JSP的部分創作者,不停地對於架構的使用,而忘記了這門語言的本質。
我覺得這個例子,再次證明了語言只是思想表達的載體。無外掛程式無架構,純HTML+CSS與純JavaScript加PHP就能夠實現,相容IE6。如果你打包一樣,放上防注入函數,完全可以成為自己的架構的。
對比與JSP與ASP,我在寫PHP的時候更加舒服,告別了MyEclipse/Eclipse與Visual Studio的卡爆,用著早已被批得一毛不是Dreamwaver,甚至還可以用記事本寫著網頁,半點鐘不卡。一台垃圾配置的Winxp就能夠創造出好的網站。關鍵是你的語言基本功問題了。少做點噴子,多做點工程。多接觸幾門程式設計語言。
【php】利用原生態的JavaScript Ajax為php進行MVC分層設計,相容IE6