博客列表 >PHP基础-MVC框架/服务容器/路由/门面技术综合实例

PHP基础-MVC框架/服务容器/路由/门面技术综合实例

岂几岂几
岂几岂几原创
2020年05月19日 03:28:30710浏览

MVC框架/服务容器/路由/门面技术综合实例

1. 创建库表和初始数据,代码结构

创建库表

初始数据(部分)

代码结构图

2. MVC各部分

  • 2.1 控制器类PlayerController.php
  1. <?php
  2. namespace controller;
  3. use model\facade\PlayerModel;
  4. use PDO;
  5. class PlayerController {
  6. /**
  7. * 查询球员分页数据
  8. * $p: 当前页码
  9. * $r: 每页显示记录数
  10. */
  11. public function players($p = 1, $r = 3) {
  12. // 查询球员总数
  13. $count = PlayerModel::playerCount();
  14. // 调整异常页码数值
  15. if(!filter_var($p, FILTER_VALIDATE_INT)){
  16. $p = 1;
  17. }
  18. $p < 1 ? 1 : ($p > $count ? $count : $p);
  19. if(!filter_var($r, FILTER_VALIDATE_INT)){
  20. $p = 3;
  21. }
  22. // 查询分页数据
  23. $players = PlayerModel::players($p, $r);
  24. // 加载视图文件,渲染数据
  25. require(dirname(__DIR__) . '/view/player/list.php');
  26. }
  27. // 跳转到球员信息编辑界面
  28. public function edit($id) {
  29. // 判断球员id有效性
  30. if(!filter_var($id, FILTER_VALIDATE_INT, ['option' => ['min_range' => 1]])) {
  31. echo("<script>alert('无效的参数');window.history.go(-1);</script>");
  32. exit;
  33. }
  34. // 查询球员信息
  35. $player = PlayerModel::player($id);
  36. // 加载视图模板,并渲染数据
  37. require(dirname(__DIR__) . '/view/player/edit.php');
  38. }
  39. // 保存修改
  40. public function doUpdate() {
  41. // post请求, 修改后的球员信息在其中
  42. $player = $_POST;
  43. // 执行保存
  44. PlayerModel::savePlayer($player);
  45. }
  46. // 跳转到删除确认页面
  47. public function del() {
  48. require(dirname(__DIR__) . '/view/player/del.php');
  49. }
  50. // 执行删除球员
  51. public function doDel() {
  52. // 球员id
  53. $id = filter_var($_GET['id'], FILTER_VALIDATE_INT, ['options' => ['min_range' => 1]]);
  54. // 球员列表的分页参数
  55. $pos = !empty($_GET['pos']) ? '?' . urldecode($_GET['pos']) : '';
  56. // 无效的id,不处理
  57. if(!$id) {
  58. echobr("<script>alert('无效的参数');window.location.href='/player/index.php/player/players{$pos}'</script>");
  59. }
  60. // 执行删除
  61. PlayerModel::delPlayer($id, $pos);
  62. }
  63. }
  • 2.2 模型类PlayerModel.php

    • 模型类\view\PlayerModel.php
  1. <?php
  2. namespace model;
  3. use PDO;
  4. class PlayerModel {
  5. // PDO
  6. protected $pdo = null;
  7. public function __construct(PDO $pdo)
  8. {
  9. $this->pdo = $pdo;
  10. }
  11. // 分页查询球员信息
  12. public function players($page = 1, $pageSize = 3) {
  13. // 分页起始记录偏移量
  14. $start = ($page - 1) * $pageSize;
  15. $sql = "SELECT * FROM `player` LIMIT {$start}, {$pageSize}";
  16. $players = $this->pdo->query($sql)->fetchAll(PDO::FETCH_ASSOC);
  17. return $players;
  18. }
  19. // 查询球员总数
  20. public function playerCount() {
  21. // 查询记录总数
  22. $sql = 'SELECT count(`id`) as row_count FROM `player`';
  23. $count = ($this->pdo->query($sql)->fetch(PDO::FETCH_NUM))[0] ?? 0;
  24. return $count;
  25. }
  26. // 根据id查询某个球员信息
  27. public function player($id) {
  28. $sql = "SELECT * FROM `player` WHERE `id` = ?";
  29. $stmt = $this->pdo->prepare($sql);
  30. $stmt->execute([$id]);
  31. // 查不到球员信息, 提示错误,不继续执行
  32. if ($stmt->rowCount() !== 1) {
  33. echo ("<script>alert('无效的ID值');window.history.go(-1);</script>");
  34. die;
  35. }
  36. // 获取查到的球员信息
  37. $player = $stmt->fetch(PDO::FETCH_ASSOC);
  38. return $player;
  39. }
  40. // 保存修改
  41. public function savePlayer($playerInfo) {
  42. $sql = "UPDATE `player` SET `name` = :name, `team` = :team, `height` = :height, `weight` = :weight, `position` = :position, `update_time` = :update_time WHERE `id` = :id";
  43. $param = $playerInfo;
  44. // 更新时间=当前时间
  45. $param['update_time'] = time();
  46. // 球员分页信息(返回球员列表用)
  47. $pos = $param['pos'];
  48. unset($param['pos']);
  49. $pos = empty($pos) ? '' : '?' . $pos;
  50. // PDO执行更新
  51. $stmt = $this->pdo->prepare($sql);
  52. $stmt->execute($param);
  53. // 验证更新结果
  54. if ($stmt->rowCount() === 1) {
  55. if (empty($pos))
  56. echo ("<script>alert('修改成功');window.history.back();</script>");
  57. else {
  58. $pos = urldecode($pos);
  59. echo ("<script>alert('修改成功');window.location='/player/index.php/player/players{$pos}';</script>");
  60. }
  61. } else {
  62. echo ("<script>alert('修改失败');</script>");
  63. }
  64. }
  65. // 根据球员id删除球员信息
  66. public function delPlayer($id, $pos='') {
  67. $sql = "DELETE FROM `player` WHERE `id` = :id";
  68. $stmt = $this->pdo->prepare($sql);
  69. $stmt->execute(['id' => $id]);
  70. $pos = empty($pos) ? '' : '?' . $pos;
  71. // 判断处理条数
  72. if ($stmt->rowCount() === 1) {
  73. echobr("<script>alert('删除成功');window.location.href='/player/index.php/player/players{$pos}'</script>");
  74. } else {
  75. echobr("更新失败");
  76. printfpre($stmt->errorInfo());
  77. echobr("<a href='/player/index.php/player/players{$pos}'>返回</a>");
  78. }
  79. }
  80. }
  • 模型门面类\view\facade\PlayerModel.php
  1. <?php
  2. namespace model\facade;
  3. use core\Facade;
  4. class PlayerModel extends Facade {
  5. }
  • 门面类基类\core\Facade.php
  1. <?php
  2. namespace core;
  3. // 门面类基类
  4. class Facade {
  5. // 无法解决创建类实例时的参数传输
  6. public static function __callStatic($name, $arguments) {
  7. return Container::make(lcfirst(ltrim(lcfirst(strrchr(static::class, '\\')), '\\')))->$name(...$arguments);
  8. }
  9. }
  • 2.3 视图文件
  • 球员分页列表·list.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. @import '/player/style/page_style.css';
  9. @import '/player/style/page_style.css';
  10. @import '/player/style/list.css';
  11. </style>
  12. </head>
  13. <?php
  14. // require('/pagination.php');
  15. ?>
  16. <body>
  17. <table cellspacing="0" align="center">
  18. <caption>球员列表</caption>
  19. <thead>
  20. <tr>
  21. <th>ID</th>
  22. <th>姓名</th>
  23. <th>球队</th>
  24. <th>身高(cm)</th>
  25. <th>体重(kg)</th>
  26. <th>位置</th>
  27. <th>创建时间</th>
  28. <th>修改时间</th>
  29. <th>操作</th>
  30. </tr>
  31. </thead>
  32. <tbody>
  33. <?php if (!empty($players) && count($players) > 0) : ?>
  34. <?php foreach ($players as $player) : ?>
  35. <tr>
  36. <td><?php echo $player['id']; ?></td>
  37. <td><?php echo $player['name']; ?></td>
  38. <td><?php echo $player['team']; ?></td>
  39. <td><?php echo $player['height']; ?></td>
  40. <td><?php echo $player['weight']; ?></td>
  41. <td><?php echo $player['position']; ?></td>
  42. <td><?php echo date('Y-m-d H:i:s', $player['create_time']); ?></td>
  43. <td><?php echo date('Y-m-d H:i:s', $player['update_time']); ?></td>
  44. <td>
  45. <a href="/player/index.php/player/edit?id=<?php echo $player['id']; ?>&pos=<?php echo urlencode($_SERVER['QUERY_STRING']); ?>">修改</a>
  46. <a href="/player/index.php/player/del?id=<?php echo $player['id']; ?>&name=<?php echo $player['name']; ?>&pos=<?php echo urlencode($_SERVER['QUERY_STRING']); ?>">删除</a>
  47. </td>
  48. </tr>
  49. <?php endforeach; ?>
  50. <?php else : ?>
  51. <tr>
  52. <td colspan="9">啥也没查到...</td>
  53. </tr>
  54. <?php endif ?>
  55. </tbody>
  56. </table>
  57. <?php (new \view\Pagination($count, $p, $r, 5))->echoPagination();
  58. ?>
  59. <?php //echo (new Pagination($count, $currentPage, 3, 5));
  60. ?>
  61. </body>
  62. </html>
  • 修改球员信息界面edit.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. @import url('/player/style/common.css');
  9. @import url('/player/style/edit.css');
  10. </style>
  11. </head>
  12. <body>
  13. <section>
  14. <div class="player-edit-header">修改球员信息</div>
  15. <div class="player-info">
  16. <form action="/player/index.php/player/doUpdate" method="post">
  17. <input type="hidden" name="id" value="<?php echo $player['id']; ?>">
  18. <input type="hidden" name="pos" value="<?php echo $_GET['pos']; ?>">
  19. <div class="info-item">
  20. <label for="name">姓名: </label>
  21. <input type="text" name="name" id="name" value="<?php echo $player['name']; ?>" required autofocus>
  22. </div>
  23. <div class="info-item">
  24. <label for="team">球队: </label>
  25. <input type="text" name="team" id="team" value="<?php echo $player['team']; ?>" required>
  26. </div>
  27. <div class="info-item">
  28. <label for="height">身高(cm): </label>
  29. <input type="number" name="height" id="height" value="<?php echo $player['height']; ?>" required>
  30. </div>
  31. <div class="info-item">
  32. <label for="weight">体重(kg): </label>
  33. <input type="number" name="weight" id="weight" value="<?php echo $player['weight']; ?>" required>
  34. </div>
  35. <div class="info-item">
  36. <label for="position">位置: </label>
  37. <input type="text" name="position" id="position" value="<?php echo $player['position']; ?>" required>
  38. </div>
  39. <div class="info-item">
  40. <button type="submit">保存</button>
  41. </div>
  42. </div>
  43. </form>
  44. </section>
  45. </body>
  46. </html>
  • 删除球员信息del.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. @import url('/player/style/common.css');
  9. @import url('/player/style/del.css');
  10. </style>
  11. </head>
  12. <body>
  13. <section>
  14. <span>确认要删除<strong><?php echo $_GET['name'] ?></strong>吗?</span>
  15. <a href="/0512/player.php<?php echo $_GET['pos'] ? '?' . $_GET['pos'] : ''; ?>" class="btn">取 消</a>
  16. <a href="do_del.php?id=<?php echo $_GET['id'] ?>&pos=<?php echo urlencode($_GET['pos']) ?>">确 认</a>
  17. </section>
  18. </body>
  19. </html>
  • 分页类\view\Pagination.php
  1. <?php
  2. namespace view;
  3. class Pagination
  4. {
  5. // 第一页
  6. private $start = 1;
  7. // 一页可容纳的记录数
  8. private $pageSize = 3;
  9. // 显示的页码个数
  10. private $pageNumSize = 5;
  11. // 显示的页码列表
  12. private $pageNumList = [];
  13. // 总页数
  14. private $pageCount = 0;
  15. // 页码左右偏移量
  16. private $pageNumOffset = 0;
  17. // 当前页码
  18. private $currentPage = 1;
  19. // 记录总数
  20. private $rowCount = 0;
  21. public function __construct(int $rowCount, int $currentPage = 1, int $pageSize = 3, int $pageNumSize = 5)
  22. {
  23. // 初始化各种属性
  24. $this->rowCount = $rowCount;
  25. $this->pageSize = $pageSize;
  26. $this->pageNumSize = $pageNumSize;
  27. $this->pageNumOffset = ($pageNumSize - 1) / 2;
  28. $this->pageCount = ceil(floatval($rowCount) / $pageSize);
  29. /* 当传入的当前页码效于最小页码时,初始化为1;大于最大页码时,初始化为最大页码 */
  30. $this->currentPage = $currentPage < 1 ? 1 : ($currentPage > $this->pageCount ? $this->pageCount : $currentPage);
  31. $this->getPageNumList();
  32. }
  33. /**
  34. * 获取要显示的页码列表
  35. */
  36. private function getPageNumList()
  37. {
  38. // 如果要显示的页码数量>=总页码数量,则显示所有页码。
  39. if ($this->pageCount <= $this->pageNumSize) {
  40. $this->pageNumList = range(1, $this->pageCount, 1);
  41. return;
  42. }
  43. // 起始页码,取“当前页码-页码偏移量”和起始页码的最大值。
  44. $pageNumStart = ($this->currentPage - $this->pageNumOffset) < $this->start ? $this->start : ($this->currentPage - $this->pageNumOffset);
  45. // 结束页码,取“当前页码+页码偏移量”和总页码数的最小值。
  46. $pageNumEnd = ($pageNumStart + $this->pageNumSize - 1) > $this->pageCount ? $this->pageCount : ($pageNumStart + $this->pageNumSize - 1);
  47. // 若结束页码等于总页码,则再计算一次起始页码(避免当前页到结束页码的差值小于页码偏移量的情况)
  48. if ($pageNumEnd === $this->pageCount) {
  49. // 起始页码,取“最大页码-要显示的页码数量+1”和起始页码的最大值。
  50. $pageNumStart = ($this->pageCount - $this->pageNumSize + 1) < $this->start ? $this->start : ($this->pageCount - $this->pageNumSize + 1);
  51. }
  52. // 生成要显示的页码数组
  53. $this->pageNumList = range($pageNumStart, $pageNumEnd, 1);
  54. }
  55. // 拼接字符串,形成分页HTML代码字符串。
  56. public function getPagination()
  57. {
  58. $pageHtml = '<div class="pagination">';
  59. // 首页
  60. $tmpHtml = $this->currentPage === 1 ? '<span class="pageNum disabled">首页</span>'
  61. : sprintf('<a class="pageNum" href="%s?p=1&r=%d">首页</a>', $_SERVER['PHP_SELF'], $this->pageSize);
  62. $pageHtml .= $tmpHtml;
  63. // 上一页
  64. $tmpHtml = $this->currentPage === 1 ? '<span class="pageNum disabled">上一页</span>'
  65. : sprintf('<a class="pageNum" href="%s?p=%d&r=%d">上一页</a>', $_SERVER['PHP_SELF'], $this->currentPage - 1, $this->pageSize);
  66. $pageHtml .= $tmpHtml;
  67. // 间隔符
  68. $tmpHtml = $this->pageNumList[0] >= 2 ? '...' : '';
  69. $pageHtml .= $tmpHtml;
  70. // 页码
  71. foreach ($this->pageNumList as $pageNum) {
  72. $tmpHtml = $pageNum == $this->currentPage ? sprintf('<span class="active">%d</span>', $pageNum)
  73. : sprintf('<a class="pageNum {$pageNum}" href="%s?p=%d&r=%d">%d</a>', $_SERVER['PHP_SELF'], $pageNum, $this->pageSize, $pageNum);
  74. $pageHtml .= $tmpHtml;
  75. }
  76. // 间隔符
  77. $tmpHtml = $this->pageNumList[array_key_last($this->pageNumList)] + 1 <= $this->pageCount ? '...' : '';
  78. $pageHtml .= $tmpHtml;
  79. // 下一页
  80. $tmpHtml = $this->currentPage >= $this->pageCount ? '<span class="pageNum disabled">下一页</span>'
  81. : sprintf('<a class="pageNum" href="%s?p=%d&r=%d">下一页</a>', $_SERVER['PHP_SELF'], $this->currentPage + 1, $this->pageSize);
  82. $pageHtml .= $tmpHtml;
  83. // 末页
  84. $tmpHtml = $this->currentPage >= $this->pageCount ? '<span class="pageNum disabled">末页</span>'
  85. : sprintf('<a class="pageNum" href="%s?p=%d&r=%d">末页</a>', $_SERVER['PHP_SELF'], $this->pageCount, $this->pageSize);
  86. $pageHtml .= $tmpHtml;
  87. // 总页码
  88. $pageHtml .= "<span>共{$this->pageCount}页</span>";
  89. // 页码跳转表单
  90. $tmpHtml = "<form action='{$_SERVER['PHP_SELF']}' method='get'> <input type='text' name='p'><input type='hidden' name='r' value='{$this->pageSize}'><button type='submit'>跳转</button></form>";
  91. $pageHtml .= $tmpHtml;
  92. $pageHtml .= '</div>';
  93. return $pageHtml;
  94. }
  95. // 直接向浏览器输出分页信息
  96. public function echoPagination()
  97. {
  98. echo $this->getPagination();
  99. }
  100. }

3. MVC框架运行类

  • 3.1 文件自动加载器autoload.php
  1. <?php
  2. # 自动加载函数
  3. // 封装自动加载器
  4. try {
  5. // 系统函数: spl_autoload_register(), 把demo8中加载文件的代码复制过来
  6. spl_autoload_register(function ($className) {
  7. // 1. 将类名中的反斜线改为当前系统中的目录分隔符
  8. $path = str_replace('\\', DIRECTORY_SEPARATOR, $className);
  9. // echobr($path);
  10. // 2. 生成真正要加载的类文件名称
  11. /* autoload.php放到core目录中,所以需要用dirname()函数来获取上一级目录的路径 */
  12. $file = dirname(__DIR__) . DIRECTORY_SEPARATOR . $path . '.php';
  13. // echobr($file);
  14. // 3. 加载这个文件
  15. require $file;
  16. });
  17. } catch (Exception $e) {
  18. die($e->getMessage());
  19. }
  • 3.2 服务容器类\core\Container.php
  1. <?php
  2. namespace core;
  3. // 服务容器类
  4. class Container {
  5. // 类实例容器
  6. protected static $instances = [];
  7. // 私有化构造方法
  8. private function __construct(){
  9. }
  10. // 把类实例的创建闭包绑定到容器中(约定别名为小驼峰类名)
  11. public static function bind($alias, \Closure $process) {
  12. static::$instances[$alias] = $process;
  13. }
  14. // 从容器中获取类实例
  15. public static function make($alias, array $param=[]) {
  16. return isset($alias) ? static::$instances[$alias](...$param) : false;
  17. }
  18. // 销毁类实例
  19. public static function destroy($alias) {
  20. unset(static::$instances[$alias]);
  21. }
  22. }
  • 3.3 路由解析类\core\Route.php
  1. <?php
  2. namespace core;
  3. class Route {
  4. public static $config = [
  5. 'controller_suffix' => 'Controller',
  6. 'action_suffix' => '',
  7. 'view_suffix' => 'View',
  8. 'model_suffix' => 'Model',
  9. ];
  10. /**
  11. * 解析路由,约定:若存在路径信息,则以路径信息的前两位作为controller和action,剩下的路径信息参数跟查询参数合并作为action的
  12. * 入参;若路径信息小于2,则action由查询参数的第一个键值对指定,剩下的查询参数作为action的入参;
  13. */
  14. public static function analysis() {
  15. // 加载配置文件
  16. $config = require((dirname(__DIR__)) . '/config.php');
  17. array_merge(static::$config, $config);
  18. // 处理路径信息
  19. $pathInfoParam = empty($_SERVER['PATH_INFO']) ? [] : static::analysisPathInfo($_SERVER['PATH_INFO']);
  20. // 处理查询字符串
  21. $queryStrParam = empty($_SERVER['QUERY_STRING']) ? [] : static::analysisQueryStr($_SERVER['QUERY_STRING']);
  22. $reqInfo = $pathInfoParam;
  23. // 路径信息和查询字符串解析结果中都没有控制器信息,则不再继续
  24. if(!isset($reqInfo['controller']) && !isset($queryStrParam['c'])) {
  25. echobr('无法处理的URL,未指定控制器');die;
  26. }
  27. // 否则,优先考虑使用路径信息中的控制器;最后再考虑使用请求参数中指定的控制器(参数名为c)
  28. if(isset($reqInfo['controller'])) {
  29. unset($queryStrParam['c']);
  30. } else {
  31. $reqInfo['controller'] = $queryStrParam['c'];
  32. unset($queryStrParam['c']);
  33. }
  34. // 路径信息和查询字符串解析结果都没有方法信息,则不再继续
  35. if(!isset($reqInfo['action']) && !isset($queryStrParam['c'])) {
  36. echobr('无法处理的URL,未指定action');die;
  37. }
  38. // 否则,优先考虑使用路径信息中的方法,最后在考虑使用请求参数中指定的方法(参数名为a)
  39. if(isset($reqInfo['action'])) {
  40. unset($queryStrParam['a']);
  41. } else {
  42. $reqInfo['action'] = $queryStrParam['a'];
  43. unset($queryStrParam['a']);
  44. }
  45. // 合并action的参数
  46. if(count($queryStrParam) > 0) {
  47. $reqInfo['param'] = array_merge($reqInfo['param'], $queryStrParam);
  48. }
  49. return $reqInfo;
  50. }
  51. // 解析路径信息
  52. private static function analysisPathInfo($pathInfo) : array {
  53. // 保存路径信息解析结果的数组
  54. $pathInfoParam = ['param' => []];
  55. // 切割字符串,形成数组
  56. $pathInfoArr = explode('/', trim($pathInfo, '/'));
  57. $paramCount = count($pathInfoArr);
  58. // 解析出来,有值,那么弹出第一个作为控制器
  59. if($paramCount > 0) {
  60. $pathInfoParam['controller'] = lcfirst(array_shift($pathInfoArr)) . static::$config['controller_suffix'];
  61. }
  62. // 值数量超过1个,则再弹出第二个作为方法
  63. if($paramCount > 1) {
  64. $pathInfoParam['action'] = lcfirst(array_shift($pathInfoArr)) . static::$config['action_suffix'];
  65. }
  66. // 值数量超过3个,则剩下的拼成参数键值对
  67. if($paramCount > 2) {
  68. for($index = 0; $index < count($pathInfoArr); $index += 2) {
  69. if(isset($pathInfoArr[$index + 1])) {
  70. $param[$pathInfoArr[$index]] = $pathInfoArr[$index + 1];
  71. }
  72. }
  73. $pathInfoParam['param'] = $param;
  74. }
  75. return $pathInfoParam;
  76. }
  77. // 解析查询参数
  78. private static function analysisQueryStr($queryStr) {
  79. // echobr($queryStr);
  80. $queryStrParam = [];
  81. parse_str($queryStr, $queryStrParam);
  82. return $queryStrParam;
  83. }
  84. }
  • 3.4 框架运行类\core\Runner.php
  1. <?php
  2. namespace core;
  3. use controller\PlayerController;
  4. use model\PlayerModel;
  5. use PDO;
  6. class Runner {
  7. private static $init = false;
  8. public static function run() {
  9. // 解析路由
  10. $reqInfo = Route::analysis();
  11. // 获取控制器
  12. $controller = Container::make($reqInfo['controller']);
  13. // 执行控制器方法
  14. $action = $reqInfo['action'];
  15. //echobr($action);
  16. $controller->$action(...array_values($reqInfo['param']));
  17. }
  18. // 把创建类实例的闭包放入容器中
  19. public static function init() {
  20. if(self::$init) return;
  21. // pdo
  22. $alias = 'pdo';
  23. Container::bind($alias, function() {
  24. return new PDO('mysql:host=localhost;dbname=phpedu;charset=utf8;port=3306', 'root', 'root');
  25. });
  26. // 默认用类的小驼峰命名作为别名
  27. $alias = lcfirst(ltrim(strrchr(PlayerModel::class, '\\'), '\\'));
  28. Container::bind($alias, function () {
  29. $pdo = Container::make('pdo');
  30. return new PlayerModel($pdo);
  31. });
  32. // 控制器
  33. $alias = lcfirst(ltrim(strrchr(PlayerController::class, '\\'), '\\'));
  34. Container::bind($alias, function() {
  35. return new PlayerController;
  36. });
  37. self::$init = true;
  38. }
  39. }
  • 3.5 配置类config.php
  1. <?php
  2. return [
  3. 'controller_suffix' => 'Controller',// 控制器后缀
  4. 'action_suffix' => '',// 方法后缀
  5. 'view_suffix' => 'View',// 视图后缀
  6. 'model_suffix' => 'Model',// 模型后缀
  7. ];
  • 3.6 入口文件index.php
  1. <?php
  2. use core\Runner;
  3. require('../out.php');
  4. require('core/autoload.php');
  5. // 前端控制器
  6. // 把创建类闭包放入容器
  7. Runner::init();
  8. // go! go! go!
  9. Runner::run();

运行结果:

与查询分类作业一样: 查询分类作业链接

学习心得

  • 把路由, 服务容器和MVC框架的作业用一个小实例实现了.

  • 实现过程遇到的问题:

      1. 如何实现自动把创建类实例的闭包放入容器中(即Runner::init()方法如何自动实现)?
      1. 创建类实例的闭包, 如何判断参数所属类型,并在容器中找到并注入? 若参数顺序和构造方法的形参顺序不一致, 如何传参?
      1. 执行控制器的方法时, 如何判断参数所属类型,假设为对象,如何在容器中查找并注入? 若参数顺序和action方法的形参顺序不一致, 如何传参?
声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议