经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » PHP » 查看文章
PHP MVC框架【Myphp】的编写
来源:cnblogs  作者:)ops  时间:2019/11/1 8:54:10  对本文有异议

1、什么是MVC

MVC(Model-View-Controller)是软件工程的一种软件架构模式。

在MVC模式设计下,软件系统被分来三个模块:模型(Model)、视图(VIew)、控制器(Controller)。

PHP下的MVC模式又称为Web MVC,自上世纪70年代进化而来。

使用MVC模式的目的是:实现一种动态的程序设计,便于后续对程序的修改和拓展,且使得程序的某一部分的重复利用成为可能。

MVC各模块的职能:

  • 模型Model:管理大部分的业务逻辑和所有的数据库逻辑。模型抽象简化了连接和操作数据库的操作。
  • 控制器Controller:负责响应用户请求、准备数据,决定如何展示数据。
  • 视图View:负责数据渲染,通过HTML方式呈现给用户。

一个典型的Web MVC 处理流程:

  1. Controller接受到用户发来的请求;
  2. Controller调用Model完成对状态的读写操作;
  3. Controller把数据传递给View;
  4. 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

整个项目的目录结构如下:

  1. MyPhpFrame1 web框架部署根目录
  2. ├─application      应用目录
  3. ├─controllers    控制器目录
  4. ├─models      模块目录 
  5. └─views       视图目录
  6. ├─config        配置文件目录
  7. ├─myphp       框架核心目录
  8. ├─runtime 运行临时目录
  9. ├─static 静态文件目录
  10. ├─.htaccess Apache目录配置
  11. └─index.php 入口文件

MyPhpFrame1位于Apache站点根目录之下。通过访问 http://localhost/MyPhpFrame1 ,可以访问到该项目。

3.3 重定向

 3.2展示的目录中.htaccess文件,是Apache服务器的目录级别的分布式配置文件,可以针对特定目录改变Apache配置。

.htaccess 可以帮我们实现:重写URL、网页301重定向、自定义404错误页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能。

Apache服务器通过启用AllowOverride All实现对应目录下的配置可重写。

本框架下.htaccess文件内容为:

 

  1. <IfModule mod_rewrite.c>
  2. #打开Rerite功能
  3. RewriteEngine On
  4. # 如果请求的是真实存在的文件f或目录d,直接访问
  5. RewriteCond %{REQUEST_FILENAME} !-f
  6. RewriteCond %{REQUEST_FILENAME} !-d
  7. #重定向所有请求到index.php?url=原路径
  8. RewriteRule ^(.*)$ index.php?url=$1 [PT,L]
  9. #[PT] passthrough,使得RewriteRule的结果重写加入到URL的匹配中
  10. #[L] last,使得mod_rewrite 停止处理规则集
  11. </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 代码规范

代码规范如下:

  1. MySQL的表名:使用小写字母与下划线(_)命名,如:item、bus_info
  2. Model模块名:使用大驼峰法(首字母大写),并在名称后加上Model,如:ItemModel、BusModel
  3. Controller控制器名:使用大驼峰法(首字母大写),并在名称后加上Controller,如:ItemController、BusController
  4. Action方法名:使用小驼峰法(首字母小写),如:index、selectAll
  5. View视图 部署结构为:控制器名/行为名,如:item/index.php、item/manage.php

使用代码规范的目的:使得程序能更好地相互调用。

4、PHP MVC核心框架

4.1 入口文件

index.php为整个项目的入口文件,位于项目根目录/下。

文件内容为:

  1. <?php
  2. header("Content-Type: text/html; charset=utf-8");
  3. //设置返回包编码方式,避免页面乱码
  4. //初始化常量
  5. define('APP_PATH',__DIR__.'/');//网站根目录
  6. define('CONFIG_PATH',APP_PATH.'config/');//网站配置目录
  7. define('APP_DEBUG',false);//开启调试模式
  8. define('APP_URL','http://localhost/MyPhpFrame1/');//网站URL
  9. define('RUNTIME_PATH',APP_PATH.'runtime/');//网站临时目录
  10. //加载配置文件
  11. require CONFIG_PATH.'/config.php';
  12. //加载框架核心文件
  13. require APP_PATH.'myphp/MyPhp.php';
  14. //实例化框架类,并执行run()方法
  15. $myphp=new Myphp();
  16. $myphp->run();

 

可以看到,上面的php代码并没有使用php结束符 ?>。

纯php代码中php结束符是可选的,提倡不写php结束符。如果这个是一个被别人require的php文件,没有这个结束符,可以避免多余输出(也就是?>之后的任何数据,包括空格、换行符等)导致header, setcookie, session_start函数执行的失败(这几个函数执行前,不允许展示任何数据)。

4.2 配置文件

config.php是项目的配置文件。位于config/目录下。

config.php的作用是:定义数据库连接参数,配置默认控制器名和默认动作名。

config.php文件内容为:

  1. <?php
  2. //数据库连接参数
  3. define('DB_NAME','myphpdb');
  4. define('DB_USER','root');
  5. define('DB_PASSWORD','root');
  6. define('DB_HOST','localhost');
  7. //默认控制器名和默认方法名
  8. define('DEFAULT_CONTROLLER','Item');
  9. define('DEFAULT_ACTION','index');

4.3 框架核心类

MyPhp.php是MyPhp框架的核心类文件。位于myphp/目录下。

 在入口文件中,对框架类做了两步操作:实例化、调用run()方法。

run()方法调用了框架类自身方法,完成以下操作:

  1. 类自动重载
  2. 环境设置
  3. 清理转义字符
  4. 移除全局变量
  5. 处理路由

MyPhp.php文件内容为:

  1. <?php
  2. /**
  3. * MyPhp核心框架类
  4. */
  5.  
  6. //初始化常量
  7. defined('APP_PATH') or define('APP_PATH',__DIR__.'\\');
  8. defined('APP_URL')or define('APP_URL','http://localhost/MyPhpFrame1');
  9. defined('APP_DEBUG') or define('APP_DEBUG',false);
  10. defined('CONFIG_PATH') or define('CONFIG_PATH',APP_PATH.'config\\');
  11. defined('RUNTIME_PATH') or define('RUNTIME_PATH',APP_PATH.'runtime/');
  12. defined('DEFAULT_CONTROLLER') or define('DEFAULT_CONTROLLER','Item');
  13. defined('DEFAULT_ACTION') or define('DEFAULT_ACTION','index');
  14. class MyPhp
  15. {
  16. /**
  17. *运行程序
  18. */
  19. function run()
  20. {
  21. spl_autoload_register(array($this,'loadClass'));
  22. //spl_autoload_register — 注册给定的函数作为 __autoload 的实现
  23. //__autoload — 尝试加载未定义的类。当我们实例化一个未定义的类时,就会触发此函数
  24. $this->setReporting();
  25. $this->removeMagicQuotes();
  26. $this->unregisterGlobals();
  27. $this->Route();
  28. }
  29. /**
  30. *路由处理
  31. *abc.com/controllerName/actionName/queryString
  32. * eg:
  33. * 访问url:localhost/item/show/name/1
  34. * 进入到route方法后,分割url,获得:
  35. * $controller:item
  36. * action:show
  37. * QueryString:array(name,1)
  38. * 然后,实例化一个新控制器:itemController,并调用itemController->show()方法
  39. */
  40. function Route()
  41. {
  42. $controllerName=DEFAULT_CONTROLLER;
  43. $actionName=DEFAULT_ACTION;
  44. if(!empty($_GET['url']))
  45. {
  46. $url=$_GET['url'];//http://localhost/
  47. $urlArray=explode('/',$url);//explode 把字符串打散为数组
  48. //获取控制器名
  49. $controllerName=ucfirst($urlArray[0]); //ucfirst 首字母转换为大写
  50. //获取动作名
  51. array_shift($urlArray);//array_shift 删除数组中的第一个元素,并返回被删除元素的值
  52. $actionName=empty($urlArray[0])?$actionName:$urlArray[0];
  53. //获取URL参数
  54. array_shift($urlArray);
  55. $queryString=empty($urlArray[0])?array():$urlArray;
  56. }
  57. //url数据为空时
  58. $queryString=empty($queryString)?array():$queryString;
  59. //判断控制器、方法 是否存在
  60. $controller=$controllerName.'Controller';
  61. if(!class_exists($controller))//class_exists — 检查类是否已定义
  62. {
  63. exit($controller.'控制器不存在');
  64. }
  65. elseif(!method_exists($controller,$actionName))
  66. {
  67. exit($actionName.'方法不存在');
  68. }
  69. //实例化控制器,因为控制器对象里面
  70. //还会用到控制器名和操作名,所以实
  71. //例化的时候把他们俩的名称也传入。查看Controller基类就明白。
  72. $dispatch=new $controller($controllerName,$actionName);
  73. //$dispatch保存控制器实例化后的对象,我们就可以调用它的方法,也可以向方法中传入参数
  74. //call_user_func_array 调用回调函数,并把一个数组参数作为回调函数的参数
  75. //以下等同于:$dispatch->$action($queryString)
  76. call_user_func_array(array($dispatch,$actionName),$queryString);
  77. }
  78. /*
  79. * 设置开发环境
  80. * */
  81. function setReporting()
  82. {
  83. if(APP_DEBUG===true)
  84. {
  85. error_reporting(E_ALL); // 报告所有错误
  86. ini_set('display_errors','On');
  87. //ini_set 设置指定配置选项的值。这个选项会在脚本运行时保持新的值,并在脚本结束时恢复。
  88. }else{
  89. error_reporting(E_ALL);
  90. ini_set('display_errors','Off');
  91. ini_set('log_errors','On');
  92. ini_set('error_log',RUNTIME_PATH.'logs/error.log');
  93. }
  94. }
  95. /*
  96. * 删除多余的反斜杠
  97. */
  98. function stripSlashesDeep($value)
  99. {
  100. $value=is_array($value)?array_map('stripSlashesDeep',$value):stripslashes($value);
  101. // 递归调用
  102. // stripslashes — 返回一个去除转义反斜线后的字符串(\' 转换为 ' 等等)。双反斜线(\\)被转换为单个反斜线(\)
  103. //array_map — 为数组的每个元素应用回调函数
  104. return $value;
  105. }
  106. /*
  107. * 检测转义后的字符并清除反斜杠
  108. */
  109. function removeMagicQuotes()
  110. {
  111. //get_magic_quotes_gpc 获得php配置magic_quotes_gpc的bool值
  112. //如果开启magic_quotes_gpc,则对GET、POST、COOKIE 数据自动运行addslashes()
  113. //addslashes 在预定义字符之前添加反斜杠。预定义字符:单引号',双引号",反斜杠\,NULL
  114. //magic_quotes_gpc特性已自 PHP 5.3.0 起废弃并将自 PHP 5.4.0 起移除。所以在5.4版本以后php配置文件是找不到魔术引号的配置信息的
  115. //PHP 5.4之后,get_magic_quotes_gpc统一返回false
  116. if(get_magic_quotes_gpc())
  117. {
  118. $_GET=$this->stripSlashesDeep($_GET);
  119. $_POST=$this->stripSlashesDeep($_POST);
  120. $_COOKIE=$this->stripSlashesDeep($_COOKIE);
  121. $_SESSION=$this->stripSlashesDeep($_SESSION);
  122. }
  123. }
  124. /*
  125. * 检测自定义全局变量(register globals)并移除,模拟register_globals=Off
  126. */
  127. function unregisterGlobals()
  128. {
  129. /*
  130. * register_globals的意思就是注册为全局变量,5.4之后已被弃用。当register_globals=On时,
  131. * 局部变量的在脚本的全局域也可用(eg:$_GET['a']也将以$a的形式存在)
  132. * 这样写是不好的实现,会影响代码中的其他变量
  133. */
  134. if(ini_get('register_globals'))
  135. {
  136. $array=array('_SESSION','_POST','_GET','_COOKIE','_REQUEST','_SERVER','_ENV','_FILES');
  137. foreach ($array as $value){
  138. echo $value;
  139. foreach($GLOBALS[$value]as $key=>$var)//处理每个内置数组中每个键值对
  140. {
  141. if($var===$GLOBALS[$key]){//如果变量值等于全局变量中对应同名的变量值
  142. unset($GLOBALS[$key]);//销毁对应的全局变量
  143. }
  144. }
  145. }
  146. }
  147. }
  148. /*
  149. * 自动加载控制器和模型类
  150. */
  151. static function loadClass($class)
  152. {
  153. //echo '执行loadClass('.$class.')<br />';
  154. $frameworks=__DIR__ . '\\'.$class.'.class.php';
  155. $controllers=APP_PATH.'application\\controllers\\'.$class.'.php';
  156. $models=APP_PATH.'application\\models\\'.$class.'.php';
  157. //echo $frameworks.'<br/>';
  158. //echo $controllers.'<br/>';
  159. //echo $models.'<br/>';
  160. if(file_exists($frameworks)){
  161. //加载核心框架类
  162. //echo '开始加载 框架核心类:'.$frameworks.'<br />';
  163. include $frameworks;
  164. //echo '成功加载 框架核心类:'.$frameworks.'<br />';
  165. }
  166. elseif (file_exists($controllers))
  167. {
  168. //echo '开始加载 应用控制器类:'.$controllers.'<br />';
  169. //加载应用控制器类else
  170. include $controllers;
  171. //echo '成功加载 应用控制器类:'.$controllers.'<br />';
  172. }
  173. elseif (file_exists($models))
  174. {
  175. //echo '开始加载 应用模型类:'.$models.'<br />';
  176. //加载应用模型类
  177. include $models;
  178. //echo '成功加载 应用模型类:'.$models.'<br />';
  179. }
  180. else{
  181. //加载失败代码
  182. exit('加载核心类文件失败!');
  183. }
  184. //echo 'loadClass('.$class.')结束<br />';
  185. }
  186. }

讲解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部分:controllerNameactionName、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,主要功能就是对整个程序进行调度,文件内容为:

  1. <?php
  2. /**
  3. * 控制器基类
  4. */
  5.  
  6. class Controller
  7. {
  8. protected $_controller; //控制器名
  9. protected $_action; //动作名
  10. protected $_view; //视图对象
  11. //构造函数:初始化属性,并实例化对应视图模型
  12. function __construct($controller,$action)
  13. {
  14. $this->_controller=$controller;
  15. $this->_action=$action;
  16. $this->_view=new View($controller,$action);
  17. }
  18. //分配变量
  19. //Controller 类用assign()方法实现把变量保存到View对象中。
  20. //这样,应用Controller调用父类Controller的 $this->render()后,视图文件就可以显示这些变量。
  21. function assign($name,$value)
  22. {
  23. $this->_view->assign($name,$value);
  24. }
  25. //渲染视图
  26. function render()
  27. {
  28. // TODO: Implement __destruct() method.
  29. $this->_view->render();
  30. }
  31. }

Controller类通过 assign()方法 实现了变量从Controller对象到VIew对象的传递(VIew类的assign就是将数据保存到自己数组中)。

这样,Controller类在调用$this->render()后,视图对象就可以渲染展示这些变量了。

4.5 模型Model基类

在myphp/目录下,新建一个模型基类,文件名为Model.class.php,文件内容为:

  1. <?php
  2. /**
  3. * 模型基类
  4. */
  5.  
  6. class Model extends Sql
  7. {
  8. protected $_model;
  9. protected $_table;
  10. function __construct()
  11. {
  12. //连接数据库
  13. $this->connect(DB_HOST,DB_USER,DB_PASSWORD,DB_NAME);
  14. //获取模型类名称
  15. $this->_model=get_class($this);
  16. $this->_model=rtrim($this->_model,'Model');//rtrim 从字符串右侧移指定字符
  17. //模型类名称与数据库中的表名一致
  18. $this->_table=strtolower($this->_model);
  19. }
  20. function __destruct()
  21. {
  22. // TODO: Implement __destruct() method.
  23. }
  24. }

可以看到,model基类继承了Sql类。

因为数据操作比较复杂,所以我为这部分操作单独创建了一个Sql类。

在myphp/目录下,新建一个Sql类,文件名为Sql.class.php,文件内容为:

  1. <?php
  2. /**
  3. * 数据库操作类
  4. */
  5.  
  6. class Sql
  7. {
  8. protected $_dbHandle;
  9. protected $_result;
  10. //连接数据库
  11. public function connect($host,$user,$pass,$dbname)
  12. {
  13. try{
  14. $dsn=sprintf("mysql:host=%s;dbname=%s;charset=utf8",$host,$dbname);//sprintf 把百分号(%)符号替换成一个作为参数进行传递的变量:
  15. $options=array(PDO::ATTR_DEFAULT_FETCH_MODE=>PDO::FETCH_ASSOC);
  16. //PDO::FETCH_ASSOC:返回一个索引为结果集列名的数组
  17. $this->_dbHandle=new PDO($dsn,$user,$pass,$options);
  18. }
  19. catch(PDOException $e)
  20. {
  21. exit('错误:'.$e->getMessage());
  22. }
  23. }
  24. //查询所有数据
  25. public function selectAll()
  26. {
  27. $sql=sprintf("select * from `%s`",$this->_table);
  28. $sth=$this->_dbHandle->prepare($sql);
  29. $sth->execute();
  30. return $sth->fetchAll();
  31. }
  32. //根据条件(id)查询
  33. public function select($id)
  34. {
  35. $sql=sprintf("select * from `%s` where `id`='%s'",$this->_table,$id);
  36. $sth=$this->_dbHandle->prepare($sql);
  37. $sth->execute();
  38. return $sth->fetch();
  39. }
  40. //根据条件(id)删除
  41. public function delete($id)
  42. {
  43. $sql=sprintf("delete from `%s` where `id`='%s'",$this->_table,$id);
  44. $sth=$this->_dbHandle->prepare();
  45. $sth->execute();
  46. return $sth->rowCount();
  47. }
  48. //自定义sql查询语句,返回影响的行数
  49. public function query($sql)
  50. {
  51. $sth=$this->_dbHandle->prepare($sql);
  52. $sth->execute($sql);
  53. return $sth->rowCount();
  54. }
  55. //新增数据
  56. public function add($data)
  57. {
  58. $sql=sprintf("insert into `%s` %s",$this->_table,$this->formatInsert($data));
  59. return $this->query($sql);
  60. }
  61. //修改数据
  62. public function update($id,$data)
  63. {
  64. $sql=sprintf("update `%s` set %s where `id`='%s'",$this->_table,$this->formatUpdate($data),$id);
  65. return $this->query($sql);
  66. }
  67. //将数组转换为insert语句中的数据格式
  68. /*
  69. $array=array("id"=>1,"name"=>"jack","age"=>19);
  70. formatInsert($array)返回字符串:
  71. (`id`,`name`,`age`) values ('1','jack','19')
  72. */
  73. private function formatInsert($data)
  74. {
  75. $fields=array();
  76. $values=array();
  77. foreach($data as $key=>$value)
  78. {
  79. $fields[]=sprintf("`%s`",$key);
  80. $values[]=sprintf("'%s'",$value);
  81. }
  82. $filed=implode(',',$fields);//implode 把数组元素组合为字符串:
  83. $value=implode(',',$values);
  84. return sprintf("(%s) values (%s)",$filed,$value);
  85. }
  86. //将数组转换为update语句中的数据格式
  87. /*
  88. $array=array("name"=>"jack","age"=>19);
  89. formatUpdate($array)返回字符串:
  90. `name`='1',`jack`='19'
  91. */
  92. private function formatUpdate($data)
  93. {
  94. $fields=array();
  95. foreach ($data as $key=>$value)
  96. {
  97. $fields[]=sprintf("`%s`='%s'",$key,$value);
  98. }
  99. return implode(',',$fields);
  100. }
  101. }

4.6 视图View基类

在myphp/目录下,新建一个视图基类,文件名为View.class.php,文件内容为:

  1. <?php
  2. /**
  3. * 视图基类
  4. */
  5.  
  6. class View
  7. {
  8. protected $variables=array();
  9. protected $_controller;
  10. protected $_action;
  11. function __construct($controller,$action)
  12. {
  13. $this->_controller=$controller;
  14. $this->_action=$action;
  15. }
  16. //导入变量
  17. function assign($name,$value)
  18. {
  19. $this->variables[$name]=$value;
  20. }
  21. //渲染显示
  22. function render()
  23. {
  24. extract($this->variables);
  25. //extract - 用来将一个数组分解成多个变量直接使用。
  26. $defaultHeader=APP_PATH.'application/views/header.php';
  27. $defaultFooter=APP_PATH.'application/views/footer.php';
  28. $controllerHeader=APP_PATH.'application/views/'.$this->_controller.'/header.php';
  29. $controllerFooter=APP_PATH.'application/views/'.$this->_controller.'/footer.php';
  30. //页头文件
  31. if(file_exists($controllerHeader))
  32. {
  33. include ($controllerHeader);
  34. }
  35. else {
  36. include ($defaultHeader);
  37. }
  38. //页内容文件
  39. include (APP_PATH.'application/views/'.$this->_controller.'/'.$this->_action.'.php');
  40. //页脚文件
  41. if(file_exists($controllerFooter))
  42. {
  43. include ($controllerFooter);
  44. } else {
  45. include ($defaultFooter);
  46. }
  47. }
  48. }

至此,核心的PHP MVC框架核心就搭建完成了。

下面,我要编写基于框架的应用代码来测试这个框架的功能。

5、基于框架的应用

5.1 部署数据库

在SQL中新建一个数据库 myphpdb,增加一个item表,并插入表中2个记录,SQL命令如下:

  1. CREATE DATABASE `myphpdb` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
  2. USE `myphpdb`;
  3. CREATE TABLE `item`(
  4. `id` int(11) NOT NULL auto_increment,
  5. `item_name` varchar(255) NOT NULL,
  6. PRIMARY KEY (`id`)
  7. )ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
  8. INSERT INTO `item` VALUES(1,'Hello World.');
  9. INSERT INTO `item` VALUES(2,'Let\'s go!');

5.2 部署模型

在application/models/目录下,创建一个ItemModel.php文件,主要功能是增加了检索数据的业务逻辑,文件内容为:

  1. <?php
  2. /**
  3. * 用户Model
  4. */
  5. class ItemModel extends Model
  6. {
  7. /**
  8. * 自定义当前模型操作的数据库表名称
  9. * 如果不指定,则默认为类名称的小写字符串,
  10. * 此处为item 表
  11. * */
  12. public $_table='item';
  13. /**
  14. * 搜索功能,以为sql父类中,并没有现成的like搜索
  15. * 所以需要自己写sql语句,对数据库的操作应该都放
  16. * 在Model中,然后提供给Controller直接调用
  17. */
  18. public function search($keyword)
  19. {
  20. $sql=sprintf("select * from `%s` where `item_name` like '%%%s%%'",$this->_table,$keyword);
  21. $sth=$this->_dbHandle->prepare($sql);
  22. $sth->execute();
  23. return $sth->fetchAll();
  24. }
  25. }

因为 Item 模型继承了 Model基类,所以它拥有 Model 基类的所有功能。

5.3 部署控制器

在application/controllers/目录下,创建一个ItemController.php文件,主要功能是准备数据、调用对应的视图,文件内容为:

  1. <?php
  2. /**
  3. * Item控制器类
  4. */
  5. class ItemController extends Controller
  6. {
  7. //首页文件,测试myphp框架自定义的sql查询
  8. public function index()
  9. {
  10. $keyword=isset($_GET['keyword'])?$_GET['keyword']:'';
  11. if ($keyword)
  12. {
  13. $items=(new ItemModel())->search($keyword);
  14. }
  15. else{
  16. $items=(new ItemModel())->selectAll();
  17. }
  18. //传入视图数据
  19. $this->assign('title','全部条目');
  20. $this->assign('keyword',$keyword);
  21. $this->assign('items',$items);
  22. //渲染试图
  23. $this->render();
  24. }
  25. //添加记录,测试myphp框架的sql查询-create
  26. public function add()
  27. {
  28. $data['item_name']=$_POST['value'];
  29. $count=(new ItemModel)->add($data);
  30. $this->assign('title','添加成功');
  31. $this->assign('count',$count);
  32. //渲染试图
  33. $this->render();
  34. }
  35. //操作管理
  36. public function manage($id=null)
  37. {
  38. $item = array();
  39. $postUrl=APP_URL.'/item/add';
  40. if($id)
  41. {
  42. $item=(new ItemModel)->select($id);
  43. $postUrl=APP_URL.'/item/update';
  44. }
  45. $this->assign('title','管理条目');
  46. $this->assign('item',$item);
  47. $this->assign('postUrl',$postUrl);
  48. //渲染试图
  49. $this->render();
  50. }
  51. //更新记录,测试框架的sql查询-update
  52. public function update()
  53. {
  54. $data=array('id'=>$_POST['id'],'item_name'=>$_POST['value']);
  55. $count=(new ItemModel)->update($data['id'],$data);
  56. $this->assign('title','修改成功');
  57. $this->assign('count',$count);
  58. //渲染试图
  59. $this->render();
  60. }
  61. //删除记录,测试框架的sql查询-delete
  62. public function delete($id=null)
  63. {
  64. $count=(new ItemModel)->delete($id);
  65. $this->assign('title','删除成功');
  66. $this->assign('count',$count);
  67. //渲染试图
  68. $this->render();
  69. }
  70. }

5.3 部署视图

在 application/views/目录下新建 header.php 和 footer.php 两个页头页脚模板文件,文件内容为:

header.php 内容:

  1. <html>
  2. <head>
  3. <meta http-equiv="Content-Type" content="text/html; charsert=utf-8"/>
  4. <title><?php echo $title; ?></title>
  5. <link rel="stylesheet" href="/static/css/main.css" type="text/css" />
  6. </head>
  7. <body>
  8. <h1>
  9. <?php echo $title; ?>
  10. </h1>

footer.php 内容:

  1. </body>
  2. </html>

页头文件使用了main.css文件,内容:

  1. html,body{
  2. margin: 0;
  3. padding: 10px;
  4. font-size: 20px;
  5. }
  6. input{
  7. color:black;
  8. font-family: Georgia, times;
  9. font-size:24px;
  10. font-weight:normal;
  11. line-height: 1.2em;
  12. }
  13. a{
  14. color:blue;
  15. font-family: Georgia,times;
  16. font-size: 20px;
  17. font-weight: normal;
  18. line-height: 1.2em;
  19. text-decoration: none;
  20. }
  21. a:hover{
  22. text-decoration: underline;
  23. }
  24. h1{
  25. color: #000000;
  26. font-size: 41px;
  27. letter-spacing: -2px;
  28. line-height: 1em;
  29. font-family: helvetica,Arial,sans-serif;
  30. border-bottom: 1px dotted #cccccc;
  31. }
  32. td{
  33. padding: 1px 30px 1px 0;
  34. }

现在,在application/view/item/目录下,创建以下几个视图文件。

index.php,作用是展示数据库中item表的所有记录、检索记录、删除记录,文件内容为:

  1. <form action="" method="get">
  2. <input type="text" value="<?php echo $keyword;?>" name="keyword">
  3. <input type="submit" value="搜索">
  4. </form>
  5.  
  6. <p>
  7. <a href="<?php echo APP_URL; ?>item/manage">新建</a>
  8. </p>
  9.  
  10. <table>
  11. <tr>
  12. <th>ID</th>
  13. <th>内容</th>
  14. <th>操作</th>
  15. </tr>
  16. <?php foreach ($items as $item):?>
  17. <tr>
  18. <td><?php echo $item['id']; ?></td>
  19. <td><?php echo $item['item_name']; ?></td>
  20. <td>
  21. <a href="<?php echo APP_URL; ?>item/manage/<?php echo $item['id']; ?>">编辑</a>
  22. <a href="<?php echo APP_URL; ?>item/delete/<?php echo $item['id']; ?>">删除</a>
  23. </td>
  24. </tr>
  25. <?php endforeach;?>
  26. </table>

manage.php,作用是编辑记录,文件内容为:

  1. <form action="<?php echo $postUrl; ?>" method="POST">
  2. <?php if(isset($item['id'])): ?>
  3. <input type="hidden" name="id" value="<?php echo $item['id']; ?>">
  4. <?php endif; ?>
  5. <input type="text" name="value" value="<?php echo isset($item['item_name'])?$item['item_name']:''; ?>">
  6. <input type="submit" value="提交">
  7. </form>
  8.  
  9. <a class="big" href="<?php echo APP_URL; ?>item/index">返回</a>

add.php,作用是提示 已添加记录,文件内容为:

  1. <a class="big" href="<?php echo APP_URL; ?>item/index">
  2. 成功添加<?php echo $count; ?>条记录,点击返回
  3. </a>

update.php,作用是提示 已修改记录,文件内容为:

  1. <a class="big" href="<?php echo APP_URL; ?>item/index">
  2. 成功修改<?php echo $count; ?>项,点击返回
  3. </a>

delete.php,作用是提示 已删除记录,文件内容为:

  1. <a href="<?php echo APP_URL; ?>item/index">
  2. 成功删除<?php echo $count; ?>项,点击返回
  3. </a>

至此,所有的应用代码已经编写完成。

6、访问应用

在浏览器中访问 http://localhost/MyPhpFrame1/  ,成功!

严重参考:

https://www.awaimai.com/128.html

https://www.cnblogs.com/Steven-shi/p/5914175.html

感谢他们的分享!!

 

原文链接:http://www.cnblogs.com/0ops/p/11762207.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号