基于MVC设计模式实现简单PHP框架(雏形)-初期
来源:互联网 发布:警官证在淘宝上怎么搜 编辑:程序博客网 时间:2024/06/06 02:23
(记住:这里只是提供思考的过程)
其实这里只是一个我们课的Web实验”课程设计题目统计系统“,在做实验的过程中起初只是想往MVC靠拢而已,却不知不觉地“实现”了基于MVC的简单框架的雏形,可能这个框架雏形还有许多BUG(毕竟这只是一个“简单”的框架而已嘛,勿喷),望读者发现后能够指出,谢谢。
该雏形并不是单一入口框架,后续还将进行修改。
这里列出的是,我做实验过程中的一些实验体会和遇到的问题:
(1) 如何将存在于控制器中的display模板呢?(参考:http://www.3lian.com/edu/2015/06-18/222798.html)
我们可以使用 include的方式引入模板,显示视图。
(2) 这里遇到了一个问题:include引入模板文件时,我使用了如 include '../showStudent.php?info=add' 的方式,结果出现了寻找不到该文件的提示,起初我以为是因为路径搞错了的原因,经过不上10几次的修改测试,最后才意识到:include文件时应该不能传递参数吧(参考:http://zhidao.baidu.com/link?url=jUrghtWyr0YljXb3rIg4aimd8_0qxq29Vqe2XMCNJQM35KLBBlIT6SUhaX82aTolSuifwRBIKHSSyTI4jbHbs_ )。是的,仔细想想,就能明白include只是用于引入文件而已,不是传递GET参数,这样当然会出错咯。我自己搞笑了。如果要传递参数,那么可以改成在include设置好变量的值不就行啦。
(3) 我们如何将变量注册到模板上呢(控制器中的变量让模板进行使用)?
(参考:php模板技术php是怎么向模板中传值的呢? http://zhidao.baidu.com/link?url=QhJKIykE8puBK82S7pW_nPzR8pMTf_tNILdG06sAgEMHQhm9bdVnjS1X4lUT68yJOLvyrILl9KixFHkVR4nSs_ )
刚才已经知道了,我们可以include文件的方式引入模板,那么我们只要在include之前定义好变量,我们就可以在模板文件中“名正言顺”地使用这些变量了。注册变量到模板的实现,可以查看一下我的源码。
(4) 注册变量到模板的过程与ThinkPHP的方式类似,实现的话,我目前没去查看ThinkPHP源码进行比较。我这里的实现需要使用到一个PHP函数——extract()(参考:http://www.w3school.com.cn/php/func_array_extract.asp )
extract() 函数从数组中将变量导入到当前的符号表。
实例
将键值 "Cat"、"Dog"和 "Horse"赋值给变量 $a、$b和 $c:
<?php
$a = "Original";
$my_array = array("a" => "Cat","b" => "Dog", "c" => "Horse");extract($my_array);
echo "\$a = $a; \$b = $b; \$c = $c";
?>
那么我们就可以使用,一个assign注册方法,提供传入两个参数,第1个参数为使用在模板上的变量名key,第2个参数为该变量的值value。先以key=>value的方式,存入到数组中,到需要显示模板的时候,我们就可以通过extract()方法将其转化为变量,变量名为key的值,变量的值为value。
(5)实现分页过程中:mysql中orderby和limit同时使用的bug(参考:http://blog.sina.com.cn/s/blog_705cc5dd01012ehb.html )
起初我的SQL语句是这样的:SELECT * FROM students LIMIT 0,20 ORDER BY sno,结果报错,应该修改为:SELECT * FROM students ORDER BY sno LIMIT 0 , 20。
(6)单一入口框架(参考:http://blog.csdn.net/qq_15096707/article/details/50766755 )
关键代码:
基本控制器类 Controller.class.php (所有自定义的控制器都将继承于该类)
<?php class Controller {const TPL_PATH = '../'; //当前控制器与模板的相对位置(实际上可以该在配置文件上)private $data = array(); //保存注册到模板上的变量/** * 验证变量是否存在,是否为空 * @param [type] $v [需要进行验证的变量] * @return [type] [true | false] */function validate($v) {if(!isset($v) || empty($v)) return false;return true;}/** * 重定向 * @param [type] $url [重定向的URL地址] * @return [type] [description] */function redirect($url) {header('Location:' . self::TPL_PATH .$url);exit;}/** * 注册模板上的变量 * @param [type] $key [应用在模板上的变量名] * @param [type] $value [变量对应的值] * @return [type] [当前对象的引用,提供链式写法] */function assign($key, $value) {$this->data[$key] = $value;return $this;}/** * 显示page模板 * @param [type] $page [模板的名称] * @return [type] [description] */function display($page) {if($this->validate($this->data)) {extract($this->data);$this->data = array();}include self::TPL_PATH . $page;}}?>
基本模型类Model.class.php(所有自定义的模型类都将继承于该类)
<?php require_once 'SqlHelper.class.php';class Model {private $sqlHelper;function __construct() {$this->sqlHelper = new SqlHelper();}function execute_dql_res($sql) {return $this->sqlHelper->execute_dql_res($sql);}function execute_dql_arr($sql) {return $this->sqlHelper->execute_dql_arr($sql);}function execute_dml($sql) {return $this->sqlHelper->execute_dml($sql);}}?>数据库操作类 SqlHelper.class.php
<?php class SqlHelper {private $mysqli;private $host = 'localhost';private $user = 'root';private $pwd = '123';private $db = 'test';private $port = 3306;public function __construct() {//完成初始化任务if(defined('SAE_MYSQL_DB')) { //判断是否是云平台$this->host = SAE_MYSQL_HOST_M;$this->user = SAE_MYSQL_USER;$this->pwd = SAE_MYSQL_PASS;$this->db = SAE_MYSQL_DB;$this->port = SAE_MYSQL_PORT;}$this->mysqli = new MySQLi($this->host, $this->user, $this->pwd, $this->db, $this->port);if($this->mysqli->connect_error) {die('连接失败' . $this->mysqli->connect_error);}//设置访问数据库的字符集//这句话的作用是保证php是以utf8的方式来操作我们的mysql数据库$this->mysqli->query("SET NAMES utf8") or die($this->mysqli->error);}public function execute_dql_res($sql) {$res = $this->mysqli->query($sql) or die('操作dql失败' . $this->mysqli->error);return $res;}public function execute_dql_arr($sql) {$arr = array();$res = $this->mysqli->query($sql) or die('操作dql失败' . $this->mysqli->error);while($row = $res->fetch_assoc()) {$arr[] = $row;}$res->free_result();return $arr;}public function execute_dml($sql) {$res = $this->mysqli->query($sql)/* or die('操作dml失败' . $this->mysqli->error)*/;if(!$res) {return 0; //表示失败} else {if($this->mysqli->affected_rows > 0) {return 1; //表示成功} else {return 2; //表示没有行受到影响}}}public function __destruct() {$this->mysqli->close();}}?>
下面是基于这个雏形的实验代码(界面采用了Bootstrap框架):
目录结构如下:
实验运行结果:
input.php
<!DOCTYPE html><html lang="zh-CN"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! --> <title>课程设计题目统计系统</title> <!-- Bootstrap --> <link href="/Lab6/Lab6_1/Public/css/bootstrap.min.css" rel="stylesheet"> <link href="/Lab6/Lab6_1/Public/style.css" rel="stylesheet" type="text/css"/> <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --> <!-- WARNING: Respond.js doesn't work if you view the page via file:// --> <!--[if lt IE 9]> <script src="//cdn.bootcss.com/html5shiv/3.7.2/html5shiv.min.js"></script> <script src="//cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script> <![endif]--> </head> <body> <div class="container"> <div class="col-sm-3"></div> <div class="col-sm-6 content"> <h2>课程设计题目统计系统</h2> <form class="form-horizontal" action="Controller/InputController.php" method="POST"> <div class="form-group"> <label for="number" class="col-sm-3 control-label">学生学号:</label> <div class="col-sm-9"> <input type="text" class="form-control" id="number" placeholder="输入12位学号" name="sno"> </div> </div> <div class="form-group"> <label for="name" class="col-sm-3 control-label">学生姓名:</label> <div class="col-sm-9"> <input type="text" class="form-control" id="name" placeholder="姓名" name="name"> </div> </div> <div class="form-group"> <label for="password" class="col-sm-3 control-label">修改密码:</label> <div class="col-sm-9"> <input type="password" class="form-control" id="password" placeholder="首次输入作为后面修改的密码" name="psw"> </div> </div> <div class="form-group"> <label for="title" class="col-sm-3 control-label">你的题目:</label> <div class="col-sm-9"> <input type="text" class="form-control" id="title" placeholder="按照课程设计题目要求" name="title"> </div> </div> <div class="form-group"> <label for="name" class="col-sm-3 control-label">合作学生:</label> <div class="col-sm-9"> <input type="text" class="form-control" id="name" placeholder="姓名,没有就空,只负责不同方面" name="partner"> </div> </div> <div class="form-group"> <div class="col-sm-offset-3 col-sm-9"> <label> <input type="radio" name="action" value="add" checked="checked"> 新增题目 </label> <label> <input type="radio" name="action" value="modify"> 修改试题 </label> </div> </div> <div class="form-group"> <div class="col-sm-offset-3 col-sm-9"> <button type="submit" class="btn btn-info">提交操作</button> <a href="Controller/showController.php">显示全部学生题目</a> </div> </div> <?php $err = array('sno'=>'学生学号不能为空!', 'name'=>'学生姓名不能为空!', 'psw'=>'修改密码不能为空', 'title'=>'题目标题不能为空!', 'add'=>'新增题目失败,原因可能为已新增过题目了,请尝试选择“修改试题”进行提交!', 'modify'=>'修改试题失败,原因可能为:1.未新增过题目;2.学生学号输入错误;3.修改密码输入错误!'); if($_GET['err']) { ?> <p class="info"><span style="font-weight: bold">错误:</span><?php echo $err[$_GET['err']];?></p> <?php } ?> </form> </div> <div class="col-sm-3"></div> </div> <!-- jQuery (necessary for Bootstrap's JavaScript plugins) --> <script src="/Lab6/Lab6_1/Public/js/jquery.min.js"></script> <!-- Include all compiled plugins (below), or include individual files as needed --> <script src="/Lab6/Lab6_1/Public/js/bootstrap.min.js"></script> </body></html>
showStudent.php
<!DOCTYPE html><html lang="zh-CN"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! --> <title>课程设计题目统计系统</title> <!-- Bootstrap --> <link href="/Lab6/Lab6_1/Public/css/bootstrap.min.css" rel="stylesheet"> <link href="/Lab6/Lab6_1/Public/style.css" rel="stylesheet" type="text/css"/> <style> p.info { margin-bottom: 0; } </style> <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --> <!-- WARNING: Respond.js doesn't work if you view the page via file:// --> <!--[if lt IE 9]> <script src="//cdn.bootcss.com/html5shiv/3.7.2/html5shiv.min.js"></script> <script src="//cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script> <![endif]--> </head> <body><div class="container"> <div class="content"> <?php if($info) { if($info == 'add') { $fo = '新增'; } else if($info == 'modify') { $fo = '修改'; } ?> <p class="info"><marquee behavior="scroll" direction="left"><span style="font-weight: bold">消息:</span><?php echo $fo . '题目成功!';?></marquee></p> <?php } ?> <table class="table table-hover"> <caption><h3>学生课程设计题目</h3></caption> <?php if(!isset($res) || empty($res)) { echo '<tr><td>暂无学生题目</td></tr>'; } else { ?> <thead> <tr> <!-- <th>删除</th> --> <th>序号</th> <th>学号</th> <th>姓名</th> <th>题目</th> <th>状态</th> <th>录入时间</th> <th>合作学生</th> </tr> </thead> <tbody> <?php $i = $start ? $start : 1; foreach ($res as $value) { echo '<tr>'; echo "<th scope='row'>$i</th>"; echo "<td>{$value['sno']}</td>"; echo "<td>{$value['name']}</td>"; echo "<td>{$value['title']}</td>"; echo "<td>{$value['state']}</td>"; echo "<td>{$value['last_time']}</td>"; echo "<td>{$value['partner']}</td>"; echo '</tr>'; $i++; } ?> </tbody> <?php } ?> </table> <nav> <ul class="pager"> <li> <?php if($prePage) { if($prePage >= 1) { echo "<a href='showController.php?cur=$prePage'>上一页</a>"; } } ?> </li> <li> <?php if($nextPage) { if($nextPage >= 1) { echo "<a href='showController.php?cur=$nextPage'>下一页</a>"; } } ?> </li> </ul> </nav> <a href="/Lab6/Lab6_1/input.php">返回输入界面</a> </div> </div> <!-- jQuery (necessary for Bootstrap's JavaScript plugins) --> <script src="/Lab6/Lab6_1/Public/js/jquery.min.js"></script> <!-- Include all compiled plugins (below), or include individual files as needed --> <script src="/Lab6/Lab6_1/Public/js/bootstrap.min.js"></script> </body></html>
style.css
body { font-family: "微软雅黑", "Microsoft YaHei"; background-color: #E8DDCB;}.content { border: 1px solid #DDD; border-radius: 5px; box-shadow: 0 0 5px #ABCEDF; padding: 0 20px 20px; background-color: #FFF; margin: 50px 0; filter:alpha(opacity=100); /* ie 有效*/ -moz-opacity: 1; /* Firefox 有效*/ opacity: 1; /* 通用,其他浏览器 有效*/ animation: contentAnim 1s; -moz-animation: contentAnim 1s; /* Firefox */ -webkit-animation: contentAnim 1s; /* Safari 和 Chrome */ -o-animation: contentAnim 1s; /* Opera */}.content h2 { text-align: center; margin: 30px 0;}@keyframes contentAnim { from {margin-top: 300px; filter:alpha(opacity=0); -moz-opacity: 0; opacity: 0;} to {margin-top: 50px; filter:alpha(opacity=100); -moz-opacity: 1; opacity: 1;}}@-moz-keyframes contentAnim { /* Firefox */ from {margin-top: 300px; filter:alpha(opacity=0); -moz-opacity: 0; opacity: 0;} to {margin-top: 50px; filter:alpha(opacity=100); -moz-opacity: 1; opacity: 1;}}@-webkit-keyframes contentAnim { /* Safari 和 Chrome */ from {margin-top: 300px; filter:alpha(opacity=0); -moz-opacity: 0; opacity: 0;} to {margin-top: 50px; filter:alpha(opacity=100); -moz-opacity: 1; opacity: 1;}}@-o-keyframes contentAnim { /* Opera */ from {margin-top: 300px; filter:alpha(opacity=0); -moz-opacity: 0; opacity: 0;} to {margin-top: 50px; filter:alpha(opacity=100); -moz-opacity: 1; opacity: 1;}}p.info { margin: 20px 0; padding: 10px 30px; background-color: #E8DDCB; border: 1px solid #CCC; border-radius: 5px;}
基本控制器类Controller.class.php 和 基本模型类 Model.class.php 在上面已经列出。
InputController.class.php
<?phprequire_once 'Controller.class.php';require_once '../Model/StudentModel.class.php';class InputController extends Controller {protected $required = array('sno'=>'学生学号不能为空!', 'name'=>'学生姓名不能为空!', 'psw'=>'修改密码不能为空', 'title'=>'题目标题不能为空!');function check() {foreach ($this->required as $key => $value) {if(!$this->validate($_POST[$key])) {$this->redirect('input.php?err=' . $key);}}}function doAction() {if($this->validate($_POST['action'])) {if($_POST['action'] == 'add') {$this->add();} else {$this->modify();}}}function add() {$studentModel = new StudentModel();if($studentModel->add()) {$this->assign('info', 'add')->show();} else {$this->redirect('input.php?err=add');}}function modify() {//echo 'modify';$studentModel = new StudentModel();if($studentModel->modify()) {$this->assign('info', 'modify')->show();} else {$this->redirect('input.php?err=modify');}}function show() {$studentModel = new StudentModel();$cur = 1; //当前页数第一页if($this->validate($_GET['cur'])) {$cur = $_GET['cur'];}$res = $studentModel->page($cur);$this->assign('res', $res)->assign('start', ($cur-1) * $studentModel->getEachPageLen() + 1)->assign('prePage', $cur-1)->assign('nextPage', $cur+1)->display('showStudent.php');}}?>
inputController.php
<?phprequire_once 'InputController.class.php';$inputC = new InputController();$inputC->check();$inputC->doAction();?>
showController.php
<?phprequire_once 'InputController.class.php';$inputC = new InputController();$inputC->show();?>
<?php require_once 'Model.class.php';class StudentModel extends Model {private $eachPageLen = 15;//新增数据function add() {$sno = $_POST['sno'];$name = $_POST['name'];$psw = $_POST['psw'];$title = $_POST['title'];$partner = $_POST['partner'];$sql = "INSERT INTO students(`sno`, `name`, `psw`, `title`, `last_time`, `partner`) VALUES('$sno', '$name', '$psw', '$title', now(), '$partner')";$res = $this->execute_dml($sql);if($res == 1) {return 1; //新增题目成功} else {return 0; //新增题目失败}}//修改数据function modify() {$sno = $_POST['sno'];$psw = $_POST['psw'];$title = $_POST['title'];$partner = !isset($_POST['partner']) || empty($_POST['partner']) ? '' : $_POST['partner'];$sql = "UPDATE students SET `title` = '$title', `partner` = '$partner' WHERE `sno` = '$sno' AND `psw` = '$psw'";$res = $this->execute_dml($sql);if($res == 1) {return 1; //修改题目成功} else {return 0; //修改题目失败}}//分页查询数据function page($cur) {$length = $this->eachPageLen;$offset = ($cur - 1) * $length;$sql = "SELECT * FROM students ORDER BY sno LIMIT $offset,$length";return $arr = $this->execute_dql_arr($sql);}//得到每页的页数function getEachPageLen() {return $this->eachPageLen;}}?>
- 基于MVC设计模式实现简单PHP框架(雏形)-初期
- PHP简单实现MVC框架路由功能模式
- MVC设计模式 简单实现
- Struts - 基于MVC设计模式的JSP (简单介绍)
- 十个目前最流行的基于MVC设计模式的PHP框架
- PHP MVC 框架的简单实现参考
- PHP扩展实现的简单MVC框架
- php实现MVC框架的简单实例
- PHP的MVC框架简单实现
- PHP之简单实现MVC框架
- werkzeug实现简单Python web框架(1):MVC模式
- php MVC设计框架
- MVC框架浅析(基于PHP)
- 框架设计模式mvc
- 基于MVC设计模式的WEB应用框架研究
- 基于MVC设计模式的WEB应用框架研究~~转
- 基于MVC设计模式的WEB应用框架研究
- 基于MVC模式的J2ME应用程序框架设计
- PHP实现最简单的登录注册
- 【一天一道LeetCode】#24. Swap Nodes in Pairs
- HDU 5671 Matrix (矩阵操作)
- 【Qt】StackedWidget
- 定位的第三方框架 LocationManager
- 基于MVC设计模式实现简单PHP框架(雏形)-初期
- C++第4次试验
- 华为OJ之学英语
- Android - Handler 、AsyncTask(二)
- BNUOJ 美女来找茬
- 01背包
- poj 3177 Redundant Paths 边双连通分量
- 在QtOpenglWidget中使用原生函数写FBO时,应注意的
- js--DOM--3.DOM2和DOM3