Blogger Information
Blog 32
fans 0
comment 0
visits 27407
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
PHP 简易MVC框架和容器的实现
Yang_Sir
Original
881 people have browsed it
  • 在代码越来越多,各种功能创建之后,就需要进行分层分类管理。依赖关系清晰,才能使程序有更好的维护性。

1.MVC框架

  • 分别建立模型类型、控制器类和视图类
  • 在控制器中调用模型获取数据,然后调用视图类输出数据展示

1.1 Model类

  • 该模型类功能主要是查询数据,所以直接继承Db数据库操作类

Model.php

  1. <?php
  2. namespace home;
  3. require 'Db.php';
  4. class Model extends Db
  5. {
  6. }

Db.php

  1. <?php
  2. namespace home;
  3. //数据库操作类
  4. class Db{
  5. public static $link = null;//保存pdo连接
  6. public static $sql = null;//保存语句
  7. //使用构造函数连接数据库
  8. public function __construct($dsn,$username,$password){
  9. try{
  10. self::$link = new \PDO($dsn,$username,$password);
  11. if(empty(self::$link)){
  12. echo '数据库连接失败';
  13. }
  14. }catch(\Exception $e){
  15. echo $e->getMessage();
  16. }
  17. }
  18. //新增数据
  19. public static function add(string $table,array $data){
  20. $val = array_values($data);
  21. $keys = array_map(function($item){
  22. return $item = '`'.$item.'`=?';
  23. },array_keys($data));
  24. $fields = implode(",",$keys);
  25. //预处理sql语句,使用占位符
  26. $sql = "insert {$table} set {$fields}";
  27. $stmt = self::$link->prepare($sql);
  28. //执行查询语句
  29. $stmt->execute($val);
  30. if($stmt->rowCount()===1){
  31. return self::$link->lastInsertId();//获取新增的主键ID
  32. }else{
  33. return $stmt->errorInfo();
  34. }
  35. }
  36. //查询数据
  37. public static function find(string $sql){
  38. //预处理sql语句
  39. $stmt = self::$link->prepare($sql);
  40. //执行查询语句
  41. $stmt->execute();
  42. return $stmt->fetchAll(\PDO::FETCH_ASSOC);
  43. }
  44. //更新数据
  45. public static function update(string $table,string $where,array $data)
  46. {
  47. $val = array_values($data);
  48. $keys = array_map(function($item){
  49. return $item = '`'.$item.'`=?';
  50. },array_keys($data));
  51. $fields = implode(",",$keys);
  52. //预处理sql语句,使用占位符
  53. self::$sql = "update `{$table}` SET {$fields} {$where}";
  54. $stmt = self::$link->prepare(self::$sql);
  55. //执行查询语句
  56. $stmt->execute($val);
  57. if($stmt->rowCount()){
  58. return $stmt->rowCount();//返回受影响的记录数
  59. }else{
  60. return $stmt->errorInfo();
  61. }
  62. }
  63. //删除数据
  64. public static function delete($table,$where)
  65. {
  66. $sql = "DELETE FROM `{$table}` {$where}";
  67. self::$sql=$sql;
  68. $stmt = self::$link->prepare($sql);
  69. $stmt->execute();
  70. if($stmt->rowCount()){
  71. return $stmt->rowCount();//返回受影响的记录数
  72. }else{
  73. return $stmt->errorInfo();
  74. }
  75. }
  76. }

1.2 View类

  • 把数据在goods.php模板文件中展示
  1. <?php
  2. namespace home;
  3. class View
  4. {
  5. public function fetch($data){
  6. include 'goods.php';
  7. }
  8. }

goods.php

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>商品信息维护</title>
  7. <style>
  8. body {
  9. display: flex;
  10. flex-flow: column nowrap;
  11. align-items: center;
  12. }
  13. form {
  14. display: flex;
  15. flex-flow: row wrap;
  16. }
  17. form>section {
  18. margin: 10px;
  19. display: flex;
  20. flex-flow: row nowrap;
  21. }
  22. table {
  23. margin-top: 30px;
  24. width: 1000px;
  25. font-family: verdana, arial, sans-serif;
  26. font-size: 11px;
  27. color: #333333;
  28. border-width: 1px;
  29. border-color: #666666;
  30. border-collapse: collapse;
  31. }
  32. table>thead {
  33. background-color: #80ff80;
  34. }
  35. table th {
  36. border-width: 1px;
  37. padding: 8px;
  38. border-style: solid;
  39. border-color: #666666;
  40. }
  41. table td {
  42. border-width: 1px;
  43. padding: 8px;
  44. border-style: solid;
  45. border-color: #666666;
  46. background-color: #ffffff;
  47. text-align: center;
  48. }
  49. tfoot>tr,
  50. tfoot>tr>td {
  51. width: initial;
  52. }
  53. </style>
  54. </head>
  55. <body>
  56. <hr>
  57. <hr>
  58. <form action="<?php echo $_SERVER['PHP_SELF'] ?>" class="queryterms" method="POST">
  59. <section>
  60. <label for="goodsname">商品名称:</label>
  61. <input type="text" name="goodsname" id="goodsname"
  62. value="<?php if(isset($_SESSION['goodsname'])) echo $_SESSION['goodsname']?>">
  63. </section>
  64. <section>
  65. <label for="goodsmodel">商品型号:</label>
  66. <input type="text" name="goodsmodel" id="goodsmodel"
  67. value="<?php if(isset($_SESSION['goodsmodel'])) echo $_SESSION['goodsmodel']?>">
  68. </section>
  69. <section>
  70. <button>查询</button>
  71. </section>
  72. </form>
  73. <div>
  74. <table>
  75. <thead>
  76. <tr>
  77. <th>ID</th>
  78. <th>名称</th>
  79. <th>型号</th>
  80. <th>价格</th>
  81. <th>数量</th>
  82. <th>状态</th>
  83. <th>操作</th>
  84. </tr>
  85. </thead>
  86. <tbody>
  87. <?php foreach($data as $val):?>
  88. <tr>
  89. <td><?php echo $val['id'] ?></td>
  90. <td><?php echo $val['name']?></td>
  91. <td><?php echo $val['model']?></td>
  92. <td><?php echo $val['price']?></td>
  93. <td><?php echo $val['number']?></td>
  94. <td><?php echo $val['status']?></td>
  95. <td><a href="handle.php?act=edit&id=<?php echo $val['id'] ?>">编辑</a>
  96. &nbsp;&nbsp;&nbsp;
  97. <a href="handle.php?act=delete&id=<?php echo $val['id'] ?>">删除</a></td>
  98. </tr>
  99. <?php endforeach; ?>
  100. </tbody>
  101. <tfoot>
  102. <tr>
  103. <td colspan="7"><?php if(isset($page))echo $page; ?></td>
  104. </tr>
  105. </tfoot>
  106. </table>
  107. </div>
  108. </body>
  109. </html>

1.3 Controller类

  • 在Controller中实例化model和view类
  • 然后调用find方法获取数据,调用fetch方法展示数据
  1. <?php
  2. namespace home;
  3. require 'Model.php';
  4. require 'View.php';
  5. //.直接在方法内实例化外部类使用
  6. class Controller
  7. {
  8. public function index($dsn,$username,$password){
  9. $data = (new Model($dsn,$username,$password))::find('select * from goods limit 2');
  10. return (new View)->fetch($data);
  11. }
  12. }
  13. $ctrl = new Controller;
  14. $ctrl->index($dsn,$username,$password);

至此,就完成了一个最简单的mvc框架,Model类负责处理数据、view输出展示数据,controller类负责接收处理请求和返回数据

效果图:

2. 容器

  • 以上mvc框架中的congtroller在类中直接实例化外部类,对外部类依赖性很强,代码耦合度高,如Model类的参数发生变化,congtroller类中也需要同步修改.
  • 如Model类中重写构造方法为不传参,而是引入文件,以上的congtroller类就需要修改
  1. <?php
  2. namespace home;
  3. require 'Db.php';
  4. class Model extends Db
  5. {
  6. public function __construct(){
  7. if(file_exists('config.php')){
  8. include 'config.php';
  9. }
  10. try{
  11. self::$link = new \PDO($dsn,$username,$password);
  12. if(empty(self::$link)){
  13. echo '数据库连接失败';
  14. }
  15. }catch(\Exception $e){
  16. echo $e->getMessage();
  17. }
  18. }
  19. }

2.1 参数依赖

  • 在此,我们可以通过参数方式传递外部类的实例来解耦
  1. // 在参数中传入外部类的实例
  2. class Controller
  3. {
  4. public function index(Model $model,view $view){
  5. $data = $model::find('select * from goods limit 2,3');
  6. return $view->fetch($data);
  7. }
  8. }
  9. $ctrl = new Controller;
  10. $ctrl->index(new Model,new View);

效果图:

通过参数传递类实例的方式,成功把模型和视图类的实例创建放到了客户端,代码涉及改造量也大大降低。但是依赖的类很多时,要一个个的创建类的实例,也比较麻烦

2.2 服务容器

  • 为解决以上问题,我们可以创建一个容器,把所有类的实例化步骤都放到该容器中,使用时直接用该类的别名即可获得该类的实例。
  • 在容器类中有两个方法,一是绑定,将类在容器中注册服务;一是取出,根据注册的类的别名获取类的实例

服务容器:

  1. <?php
  2. namespace home;
  3. //服务容器类
  4. class Container
  5. {
  6. public $binds = [];
  7. //绑定服务到容器
  8. public function bind($alias,\Closure $process){
  9. $this->binds[$alias] = $process;
  10. }
  11. //使用
  12. public function make($alias,array $param=[]){
  13. return call_user_func_array($this->binds[$alias],$param);
  14. }
  15. }

容器依赖:

  1. class Controller3
  2. {
  3. public function index(Container $container){
  4. //从容器中取得model和view类的对象实例
  5. $data = $container->make('Model')::find('select * from goods limit 6,5');
  6. return $container->make('View')->fetch($data);
  7. }
  8. }
  9. $container = new Container;
  10. //注册服务,绑定类到容器中
  11. $container->bind('Model',function(){return new Model();});
  12. $container->bind('View',function(){return new View;});
  13. $container->bind('controller',function(){return new Controller3;});
  14. //使用服务
  15. $container->make('controller')->index($container);

效果图:

服务容器就像一个全局变量,把所有服务类放到容器中,使用时根据注册的名字即可直接获得实例

Correcting teacher:天蓬老师天蓬老师

Correction status:qualified

Teacher's comments:理解了容器的概念, 写一个服务容器就简单了, 但是实际的服务容器, 比这个复杂多了,有对象, 有数组, 有闭包, 有函数, 有类, 有请求数据,甚至代码片断, 反射结果 等, 但思想是不变的
Statement of this Website
The copyright of this blog article belongs to the blogger. Please specify the address when reprinting! If there is any infringement or violation of the law, please contact admin@php.cn Report processing!
All comments Speak rationally on civilized internet, please comply with News Comment Service Agreement
0 comments
Author's latest blog post
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!