1、什么是MVC
MVC(Model-View-Controller)是軟件工程的一種軟件架構模式。
在MVC模式設計下,軟件系統被分來三個模塊:模型(Model)、視圖(VIew)、控制器(Controller)。
PHP下的MVC模式又稱為Web MVC,自上世紀70年代進化而來。
使用MVC模式的目的是:實現一種動態的程序設計,便於后續對程序的修改和拓展,且使得程序的某一部分的重復利用成為可能。
MVC各模塊的職能:
- 模型Model:管理大部分的業務邏輯和所有的數據庫邏輯。模型抽象簡化了連接和操作數據庫的操作。
- 控制器Controller:負責響應用戶請求、准備數據,決定如何展示數據。
- 視圖View:負責數據渲染,通過HTML方式呈現給用戶。
一個典型的Web MVC 處理流程:
- Controller接受到用戶發來的請求;
- Controller調用Model完成對狀態的讀寫操作;
- Controller把數據傳遞給View;
- View渲染出HTML頁面並展示給用戶。
2、為什么要自己開發MVC框架
為了做以MVC模式開發的各類CMS的代碼審計。
3、准備工作
3.1 開發環境准備
建站軟件:phpstudy2018
IDE:phpstorm2018.1
php版本:5.4.45-nts
Apache&MySQL
3.2 目錄准備
我給該Web MVC框架取名為:MyPhp
該項目目錄為:MyPhpFrame1
整個項目的目錄結構如下:
MyPhpFrame1 web框架部署根目錄 ├─application 應用目錄 │ ├─controllers 控制器目錄 │ ├─models 模塊目錄 │ └─views 視圖目錄 ├─config 配置文件目錄 ├─myphp 框架核心目錄 ├─runtime 運行臨時目錄 ├─static 靜態文件目錄 ├─.htaccess Apache目錄配置 └─index.php 入口文件
MyPhpFrame1位於Apache站點根目錄之下。通過訪問 http://localhost/MyPhpFrame1 ,可以訪問到該項目。
3.3 重定向
3.2展示的目錄中.htaccess文件,是Apache服務器的目錄級別的分布式配置文件,可以針對特定目錄改變Apache配置。
.htaccess 可以幫我們實現:重寫URL、網頁301重定向、自定義404錯誤頁面、改變文件擴展名、允許/阻止特定的用戶或者目錄的訪問、禁止目錄列表、配置默認文檔等功能。
Apache服務器通過啟用AllowOverride All實現對應目錄下的配置可重寫。
本框架下.htaccess文件內容為:
<IfModule mod_rewrite.c> #打開Rerite功能 RewriteEngine On # 如果請求的是真實存在的文件f或目錄d,直接訪問 RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d #重定向所有請求到index.php?url=原路徑 RewriteRule ^(.*)$ index.php?url=$1 [PT,L] #[PT] passthrough,使得RewriteRule的結果重寫加入到URL的匹配中 #[L] last,使得mod_rewrite 停止處理規則集 </IfModule>
這里使用該.htaccess的原因是:
1、 靜態文件可以直接訪問,比如css文件、js文件都可以直接訪問。
(如果是非index.php的php文件,可以訪問,不過由於框架特性,類之間需要extends,可能會報錯。如果是目錄,也可以訪問,如果apache開啟了目錄列表,則可以看到index of目錄,否則返回403。)
2、 程序有了單一的入口,就是index.php。
當請求地址不是真實存在的文件或目錄時,請求就會傳給index.php。
例如,訪問地址:http://localhost/MyPhpFrame1/item/index,文件系統中並不存在這樣的文件或目錄。則Apache會把重寫這個地址為:http://localhost/MyPhpFrame1/index.php?url=item/index。這樣在php中用$_GET['url']就可以拿到 item/index了。
3.4 代碼規范
代碼規范如下:
- MySQL的表名:使用小寫字母與下划線(_)命名,如:item、bus_info
- Model模塊名:使用大駝峰法(首字母大寫),並在名稱后加上Model,如:ItemModel、BusModel
- Controller控制器名:使用大駝峰法(首字母大寫),並在名稱后加上Controller,如:ItemController、BusController
- Action方法名:使用小駝峰法(首字母小寫),如:index、selectAll
- View視圖 部署結構為:控制器名/行為名,如:item/index.php、item/manage.php
使用代碼規范的目的:使得程序能更好地相互調用。
4、PHP MVC核心框架
4.1 入口文件
index.php為整個項目的入口文件,位於項目根目錄/下。
文件內容為:
<?php header("Content-Type: text/html; charset=utf-8"); //設置返回包編碼方式,避免頁面亂碼 //初始化常量 define('APP_PATH',__DIR__.'/');//網站根目錄 define('CONFIG_PATH',APP_PATH.'config/');//網站配置目錄 define('APP_DEBUG',false);//開啟調試模式 define('APP_URL','http://localhost/MyPhpFrame1/');//網站URL define('RUNTIME_PATH',APP_PATH.'runtime/');//網站臨時目錄 //加載配置文件 require CONFIG_PATH.'/config.php'; //加載框架核心文件 require APP_PATH.'myphp/MyPhp.php'; //實例化框架類,並執行run()方法 $myphp=new Myphp(); $myphp->run();
可以看到,上面的php代碼並沒有使用php結束符 ?>。
純php代碼中php結束符是可選的,提倡不寫php結束符。如果這個是一個被別人require的php文件,沒有這個結束符,可以避免多余輸出(也就是?>之后的任何數據,包括空格、換行符等)導致header, setcookie, session_start函數執行的失敗(這幾個函數執行前,不允許展示任何數據)。
4.2 配置文件
config.php是項目的配置文件。位於config/目錄下。
config.php的作用是:定義數據庫連接參數,配置默認控制器名和默認動作名。
config.php文件內容為:
<?php //數據庫連接參數 define('DB_NAME','myphpdb'); define('DB_USER','root'); define('DB_PASSWORD','root'); define('DB_HOST','localhost'); //默認控制器名和默認方法名 define('DEFAULT_CONTROLLER','Item'); define('DEFAULT_ACTION','index');
4.3 框架核心類
MyPhp.php是MyPhp框架的核心類文件。位於myphp/目錄下。
在入口文件中,對框架類做了兩步操作:實例化、調用run()方法。
run()方法調用了框架類自身方法,完成以下操作:
- 類自動重載
- 環境設置
- 清理轉義字符
- 移除全局變量
- 處理路由
MyPhp.php文件內容為:
<?php /** * MyPhp核心框架類 */ //初始化常量 defined('APP_PATH') or define('APP_PATH',__DIR__.'\\'); defined('APP_URL')or define('APP_URL','http://localhost/MyPhpFrame1'); defined('APP_DEBUG') or define('APP_DEBUG',false); defined('CONFIG_PATH') or define('CONFIG_PATH',APP_PATH.'config\\'); defined('RUNTIME_PATH') or define('RUNTIME_PATH',APP_PATH.'runtime/'); defined('DEFAULT_CONTROLLER') or define('DEFAULT_CONTROLLER','Item'); defined('DEFAULT_ACTION') or define('DEFAULT_ACTION','index'); class MyPhp { /** *運行程序 */ function run() { spl_autoload_register(array($this,'loadClass')); //spl_autoload_register — 注冊給定的函數作為 __autoload 的實現 //__autoload — 嘗試加載未定義的類。當我們實例化一個未定義的類時,就會觸發此函數 $this->setReporting(); $this->removeMagicQuotes(); $this->unregisterGlobals(); $this->Route(); } /** *路由處理 *abc.com/controllerName/actionName/queryString * eg: * 訪問url:localhost/item/show/name/1 * 進入到route方法后,分割url,獲得: * $controller:item * action:show * QueryString:array(name,1) * 然后,實例化一個新控制器:itemController,並調用itemController->show()方法 */ function Route() { $controllerName=DEFAULT_CONTROLLER; $actionName=DEFAULT_ACTION; if(!empty($_GET['url'])) { $url=$_GET['url'];//http://localhost/ $urlArray=explode('/',$url);//explode 把字符串打散為數組 //獲取控制器名 $controllerName=ucfirst($urlArray[0]); //ucfirst 首字母轉換為大寫 //獲取動作名 array_shift($urlArray);//array_shift 刪除數組中的第一個元素,並返回被刪除元素的值 $actionName=empty($urlArray[0])?$actionName:$urlArray[0]; //獲取URL參數 array_shift($urlArray); $queryString=empty($urlArray[0])?array():$urlArray; } //url數據為空時 $queryString=empty($queryString)?array():$queryString; //判斷控制器、方法 是否存在 $controller=$controllerName.'Controller'; if(!class_exists($controller))//class_exists — 檢查類是否已定義 { exit($controller.'控制器不存在'); } elseif(!method_exists($controller,$actionName)) { exit($actionName.'方法不存在'); } //實例化控制器,因為控制器對象里面 //還會用到控制器名和操作名,所以實 //例化的時候把他們倆的名稱也傳入。查看Controller基類就明白。 $dispatch=new $controller($controllerName,$actionName); //$dispatch保存控制器實例化后的對象,我們就可以調用它的方法,也可以向方法中傳入參數 //call_user_func_array 調用回調函數,並把一個數組參數作為回調函數的參數 //以下等同於:$dispatch->$action($queryString) call_user_func_array(array($dispatch,$actionName),$queryString); } /* * 設置開發環境 * */ function setReporting() { if(APP_DEBUG===true) { error_reporting(E_ALL); // 報告所有錯誤 ini_set('display_errors','On'); //ini_set 設置指定配置選項的值。這個選項會在腳本運行時保持新的值,並在腳本結束時恢復。 }else{ error_reporting(E_ALL); ini_set('display_errors','Off'); ini_set('log_errors','On'); ini_set('error_log',RUNTIME_PATH.'logs/error.log'); } } /* * 刪除多余的反斜杠 */ function stripSlashesDeep($value) { $value=is_array($value)?array_map('stripSlashesDeep',$value):stripslashes($value); // 遞歸調用 // stripslashes — 返回一個去除轉義反斜線后的字符串(\' 轉換為 ' 等等)。雙反斜線(\\)被轉換為單個反斜線(\) //array_map — 為數組的每個元素應用回調函數 return $value; } /* * 檢測轉義后的字符並清除反斜杠 */ function removeMagicQuotes() { //get_magic_quotes_gpc 獲得php配置magic_quotes_gpc的bool值 //如果開啟magic_quotes_gpc,則對GET、POST、COOKIE 數據自動運行addslashes() //addslashes 在預定義字符之前添加反斜杠。預定義字符:單引號',雙引號",反斜杠\,NULL //magic_quotes_gpc特性已自 PHP 5.3.0 起廢棄並將自 PHP 5.4.0 起移除。所以在5.4版本以后php配置文件是找不到魔術引號的配置信息的 //PHP 5.4之后,get_magic_quotes_gpc統一返回false if(get_magic_quotes_gpc()) { $_GET=$this->stripSlashesDeep($_GET); $_POST=$this->stripSlashesDeep($_POST); $_COOKIE=$this->stripSlashesDeep($_COOKIE); $_SESSION=$this->stripSlashesDeep($_SESSION); } } /* * 檢測自定義全局變量(register globals)並移除,模擬register_globals=Off */ function unregisterGlobals() { /* * register_globals的意思就是注冊為全局變量,5.4之后已被棄用。當register_globals=On時, * 局部變量的在腳本的全局域也可用(eg:$_GET['a']也將以$a的形式存在) * 這樣寫是不好的實現,會影響代碼中的其他變量 */ if(ini_get('register_globals')) { $array=array('_SESSION','_POST','_GET','_COOKIE','_REQUEST','_SERVER','_ENV','_FILES'); foreach ($array as $value){ echo $value; foreach($GLOBALS[$value]as $key=>$var)//處理每個內置數組中每個鍵值對 { if($var===$GLOBALS[$key]){//如果變量值等於全局變量中對應同名的變量值 unset($GLOBALS[$key]);//銷毀對應的全局變量 } } } } } /* * 自動加載控制器和模型類 */ static function loadClass($class) { //echo '執行loadClass('.$class.')<br />'; $frameworks=__DIR__ . '\\'.$class.'.class.php'; $controllers=APP_PATH.'application\\controllers\\'.$class.'.php'; $models=APP_PATH.'application\\models\\'.$class.'.php'; //echo $frameworks.'<br/>'; //echo $controllers.'<br/>'; //echo $models.'<br/>'; if(file_exists($frameworks)){ //加載核心框架類 //echo '開始加載 框架核心類:'.$frameworks.'<br />'; include $frameworks; //echo '成功加載 框架核心類:'.$frameworks.'<br />'; } elseif (file_exists($controllers)) { //echo '開始加載 應用控制器類:'.$controllers.'<br />'; //加載應用控制器類else include $controllers; //echo '成功加載 應用控制器類:'.$controllers.'<br />'; } elseif (file_exists($models)) { //echo '開始加載 應用模型類:'.$models.'<br />'; //加載應用模型類 include $models; //echo '成功加載 應用模型類:'.$models.'<br />'; } else{ //加載失敗代碼 exit('加載核心類文件失敗!'); } //echo 'loadClass('.$class.')結束<br />'; } }
講解2個方法:loadClass()、route()
localClass()作用是:加載未定義的類時,導入對應的類文件。
首先構造對應類的可能的文件路徑:如果對應類是核心框架類,則類文件路徑應該為$frameworks;如果對應類是應用控制器類,則類文件路徑應該為$controllers;如果對應類是應用模型類,則類文件路徑應該為$models。
接着,對每個可能存在類文件路徑,進行file_exists判定,存在則include。
則無本框架下任意類都可以完成自動加載。
route()作用是:通過url,解析出控制器名、方法名和url參數,然后實例化對應的控制器,執行對應的方法,並傳入對應的url參數。
假設瀏覽器訪問的URL為:yourhost.com/controllerName/actionName/queryString
首先,Apache會根據.htaccess重寫URL,重寫后的URL為:yourhost.com/index.php?url=controllerName/actionName/queryString
route()從全局變量$_GET['url']中獲得字符串 controllerName/actionName/queryString
然后,route()會將字符串轉換為數組,通過對數組的操作獲得3部分:controllerName、actionName、queryString。
最后,route()會實例化對應控制器,並調用對應方法。
例如,URL鏈接為:yourhost.com/item/manage/6,經過route()處理后:
- $controllerName為:Item
- $actionName為:manage
- $urlArray為:array(6)
處理完成后,route()會實例化控制器ItemController,並調用它的manage(array(6))
4.4 控制器Controller基類
接下來,就是在myphp框架中創建MVC基類,包括控制器、模型、視圖三個基類。
在myphp/目錄下,新建一個控制器基類,文件名為Controller.class.php,主要功能就是對整個程序進行調度,文件內容為:
<?php /** * 控制器基類 */ class Controller { protected $_controller; //控制器名 protected $_action; //動作名 protected $_view; //視圖對象 //構造函數:初始化屬性,並實例化對應視圖模型 function __construct($controller,$action) { $this->_controller=$controller; $this->_action=$action; $this->_view=new View($controller,$action); } //分配變量 //Controller 類用assign()方法實現把變量保存到View對象中。 //這樣,應用Controller調用父類Controller的 $this->render()后,視圖文件就可以顯示這些變量。 function assign($name,$value) { $this->_view->assign($name,$value); } //渲染視圖 function render() { // TODO: Implement __destruct() method. $this->_view->render(); } }
Controller類通過 assign()方法 實現了變量從Controller對象到VIew對象的傳遞(VIew類的assign就是將數據保存到自己數組中)。
這樣,Controller類在調用$this->render()后,視圖對象就可以渲染展示這些變量了。
4.5 模型Model基類
在myphp/目錄下,新建一個模型基類,文件名為Model.class.php,文件內容為:
<?php /** * 模型基類 */ class Model extends Sql { protected $_model; protected $_table; function __construct() { //連接數據庫 $this->connect(DB_HOST,DB_USER,DB_PASSWORD,DB_NAME); //獲取模型類名稱 $this->_model=get_class($this); $this->_model=rtrim($this->_model,'Model');//rtrim 從字符串右側移指定字符 //模型類名稱與數據庫中的表名一致 $this->_table=strtolower($this->_model); } function __destruct() { // TODO: Implement __destruct() method. } }
可以看到,model基類繼承了Sql類。
因為數據操作比較復雜,所以我為這部分操作單獨創建了一個Sql類。
在myphp/目錄下,新建一個Sql類,文件名為Sql.class.php,文件內容為:
<?php /** * 數據庫操作類 */ class Sql { protected $_dbHandle; protected $_result; //連接數據庫 public function connect($host,$user,$pass,$dbname) { try{ $dsn=sprintf("mysql:host=%s;dbname=%s;charset=utf8",$host,$dbname);//sprintf 把百分號(%)符號替換成一個作為參數進行傳遞的變量: $options=array(PDO::ATTR_DEFAULT_FETCH_MODE=>PDO::FETCH_ASSOC); //PDO::FETCH_ASSOC:返回一個索引為結果集列名的數組 $this->_dbHandle=new PDO($dsn,$user,$pass,$options); } catch(PDOException $e) { exit('錯誤:'.$e->getMessage()); } } //查詢所有數據 public function selectAll() { $sql=sprintf("select * from `%s`",$this->_table); $sth=$this->_dbHandle->prepare($sql); $sth->execute(); return $sth->fetchAll(); } //根據條件(id)查詢 public function select($id) { $sql=sprintf("select * from `%s` where `id`='%s'",$this->_table,$id); $sth=$this->_dbHandle->prepare($sql); $sth->execute(); return $sth->fetch(); } //根據條件(id)刪除 public function delete($id) { $sql=sprintf("delete from `%s` where `id`='%s'",$this->_table,$id); $sth=$this->_dbHandle->prepare(); $sth->execute(); return $sth->rowCount(); } //自定義sql查詢語句,返回影響的行數 public function query($sql) { $sth=$this->_dbHandle->prepare($sql); $sth->execute($sql); return $sth->rowCount(); } //新增數據 public function add($data) { $sql=sprintf("insert into `%s` %s",$this->_table,$this->formatInsert($data)); return $this->query($sql); } //修改數據 public function update($id,$data) { $sql=sprintf("update `%s` set %s where `id`='%s'",$this->_table,$this->formatUpdate($data),$id); return $this->query($sql); } //將數組轉換為insert語句中的數據格式 /* $array=array("id"=>1,"name"=>"jack","age"=>19); formatInsert($array)返回字符串: (`id`,`name`,`age`) values ('1','jack','19') */ private function formatInsert($data) { $fields=array(); $values=array(); foreach($data as $key=>$value) { $fields[]=sprintf("`%s`",$key); $values[]=sprintf("'%s'",$value); } $filed=implode(',',$fields);//implode 把數組元素組合為字符串: $value=implode(',',$values); return sprintf("(%s) values (%s)",$filed,$value); } //將數組轉換為update語句中的數據格式 /* $array=array("name"=>"jack","age"=>19); formatUpdate($array)返回字符串: `name`='1',`jack`='19' */ private function formatUpdate($data) { $fields=array(); foreach ($data as $key=>$value) { $fields[]=sprintf("`%s`='%s'",$key,$value); } return implode(',',$fields); } }
4.6 視圖View基類
在myphp/目錄下,新建一個視圖基類,文件名為View.class.php,文件內容為:
<?php /** * 視圖基類 */ class View { protected $variables=array(); protected $_controller; protected $_action; function __construct($controller,$action) { $this->_controller=$controller; $this->_action=$action; } //導入變量 function assign($name,$value) { $this->variables[$name]=$value; } //渲染顯示 function render() { extract($this->variables); //extract - 用來將一個數組分解成多個變量直接使用。 $defaultHeader=APP_PATH.'application/views/header.php'; $defaultFooter=APP_PATH.'application/views/footer.php'; $controllerHeader=APP_PATH.'application/views/'.$this->_controller.'/header.php'; $controllerFooter=APP_PATH.'application/views/'.$this->_controller.'/footer.php'; //頁頭文件 if(file_exists($controllerHeader)) { include ($controllerHeader); } else { include ($defaultHeader); } //頁內容文件 include (APP_PATH.'application/views/'.$this->_controller.'/'.$this->_action.'.php'); //頁腳文件 if(file_exists($controllerFooter)) { include ($controllerFooter); } else { include ($defaultFooter); } } }
至此,核心的PHP MVC框架核心就搭建完成了。
下面,我要編寫基於框架的應用代碼來測試這個框架的功能。
5、基於框架的應用
5.1 部署數據庫
在SQL中新建一個數據庫 myphpdb,增加一個item表,並插入表中2個記錄,SQL命令如下:
CREATE DATABASE `myphpdb` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; USE `myphpdb`; CREATE TABLE `item`( `id` int(11) NOT NULL auto_increment, `item_name` varchar(255) NOT NULL, PRIMARY KEY (`id`) )ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; INSERT INTO `item` VALUES(1,'Hello World.'); INSERT INTO `item` VALUES(2,'Let\'s go!');
5.2 部署模型
在application/models/目錄下,創建一個ItemModel.php文件,主要功能是增加了檢索數據的業務邏輯,文件內容為:
<?php /** * 用戶Model */ class ItemModel extends Model { /** * 自定義當前模型操作的數據庫表名稱 * 如果不指定,則默認為類名稱的小寫字符串, * 此處為item 表 * */ public $_table='item'; /** * 搜索功能,以為sql父類中,並沒有現成的like搜索 * 所以需要自己寫sql語句,對數據庫的操作應該都放 * 在Model中,然后提供給Controller直接調用 */ public function search($keyword) { $sql=sprintf("select * from `%s` where `item_name` like '%%%s%%'",$this->_table,$keyword); $sth=$this->_dbHandle->prepare($sql); $sth->execute(); return $sth->fetchAll(); } }
因為 Item 模型繼承了 Model基類,所以它擁有 Model 基類的所有功能。
5.3 部署控制器
在application/controllers/目錄下,創建一個ItemController.php文件,主要功能是准備數據、調用對應的視圖,文件內容為:
<?php /** * Item控制器類 */ class ItemController extends Controller { //首頁文件,測試myphp框架自定義的sql查詢 public function index() { $keyword=isset($_GET['keyword'])?$_GET['keyword']:''; if ($keyword) { $items=(new ItemModel())->search($keyword); } else{ $items=(new ItemModel())->selectAll(); } //傳入視圖數據 $this->assign('title','全部條目'); $this->assign('keyword',$keyword); $this->assign('items',$items); //渲染試圖 $this->render(); } //添加記錄,測試myphp框架的sql查詢-create public function add() { $data['item_name']=$_POST['value']; $count=(new ItemModel)->add($data); $this->assign('title','添加成功'); $this->assign('count',$count); //渲染試圖 $this->render(); } //操作管理 public function manage($id=null) { $item = array(); $postUrl=APP_URL.'/item/add'; if($id) { $item=(new ItemModel)->select($id); $postUrl=APP_URL.'/item/update'; } $this->assign('title','管理條目'); $this->assign('item',$item); $this->assign('postUrl',$postUrl); //渲染試圖 $this->render(); } //更新記錄,測試框架的sql查詢-update public function update() { $data=array('id'=>$_POST['id'],'item_name'=>$_POST['value']); $count=(new ItemModel)->update($data['id'],$data); $this->assign('title','修改成功'); $this->assign('count',$count); //渲染試圖 $this->render(); } //刪除記錄,測試框架的sql查詢-delete public function delete($id=null) { $count=(new ItemModel)->delete($id); $this->assign('title','刪除成功'); $this->assign('count',$count); //渲染試圖 $this->render(); } }
5.3 部署視圖
在 application/views/目錄下新建 header.php 和 footer.php 兩個頁頭頁腳模板文件,文件內容為:
header.php 內容:
<html> <head> <meta http-equiv="Content-Type" content="text/html; charsert=utf-8"/> <title><?php echo $title; ?></title> <link rel="stylesheet" href="/static/css/main.css" type="text/css" /> </head> <body> <h1> <?php echo $title; ?> </h1>
footer.php 內容:
</body> </html>
頁頭文件使用了main.css文件,內容:
html,body{ margin: 0; padding: 10px; font-size: 20px; } input{ color:black; font-family: Georgia, times; font-size:24px; font-weight:normal; line-height: 1.2em; } a{ color:blue; font-family: Georgia,times; font-size: 20px; font-weight: normal; line-height: 1.2em; text-decoration: none; } a:hover{ text-decoration: underline; } h1{ color: #000000; font-size: 41px; letter-spacing: -2px; line-height: 1em; font-family: helvetica,Arial,sans-serif; border-bottom: 1px dotted #cccccc; } td{ padding: 1px 30px 1px 0; }
現在,在application/view/item/目錄下,創建以下幾個視圖文件。
index.php,作用是展示數據庫中item表的所有記錄、檢索記錄、刪除記錄,文件內容為:
<form action="" method="get"> <input type="text" value="<?php echo $keyword;?>" name="keyword"> <input type="submit" value="搜索"> </form> <p> <a href="<?php echo APP_URL; ?>item/manage">新建</a> </p> <table> <tr> <th>ID</th> <th>內容</th> <th>操作</th> </tr> <?php foreach ($items as $item):?> <tr> <td><?php echo $item['id']; ?></td> <td><?php echo $item['item_name']; ?></td> <td> <a href="<?php echo APP_URL; ?>item/manage/<?php echo $item['id']; ?>">編輯</a> <a href="<?php echo APP_URL; ?>item/delete/<?php echo $item['id']; ?>">刪除</a> </td> </tr> <?php endforeach;?> </table>
manage.php,作用是編輯記錄,文件內容為:
<form action="<?php echo $postUrl; ?>" method="POST"> <?php if(isset($item['id'])): ?> <input type="hidden" name="id" value="<?php echo $item['id']; ?>"> <?php endif; ?> <input type="text" name="value" value="<?php echo isset($item['item_name'])?$item['item_name']:''; ?>"> <input type="submit" value="提交"> </form> <a class="big" href="<?php echo APP_URL; ?>item/index">返回</a>
add.php,作用是提示 已添加記錄,文件內容為:
<a class="big" href="<?php echo APP_URL; ?>item/index"> 成功添加<?php echo $count; ?>條記錄,點擊返回 </a>
update.php,作用是提示 已修改記錄,文件內容為:
<a class="big" href="<?php echo APP_URL; ?>item/index"> 成功修改<?php echo $count; ?>項,點擊返回 </a>
delete.php,作用是提示 已刪除記錄,文件內容為:
<a href="<?php echo APP_URL; ?>item/index"> 成功刪除<?php echo $count; ?>項,點擊返回 </a>
至此,所有的應用代碼已經編寫完成。
6、訪問應用
在瀏覽器中訪問 http://localhost/MyPhpFrame1/ ,成功!
嚴重參考:
https://www.awaimai.com/128.html
https://www.cnblogs.com/Steven-shi/p/5914175.html
感謝他們的分享!!