composer require catfan/medoocomposer require league/plates
{"require": {"catfan/medoo": "^2.0","league/plates": "^3.4"},"autoload": {"psr-4": {"app\\controllers\\": "app/controllers","app\\models\\": "app/models","app\\views\\": "app/views","core\\": "core"}}}
https://packagist.org/packages/catfan/medoo#v2.0.0
https://packagist.org/packages/league/plates#v3.4.0


core/Model.php
<?phpnamespace core;use Medoo\Medoo;/*** 继承第三方模型 atfan/medoo*///框架核心模型类文件class Model extends Medoo{public function __construct(){//mysql连接参数$config = ['database_type' => 'mysql','server' => 'localhost','database_name' => 'mydb','username' => 'root','password' => 'root'];// 给父类的构造方法传递参数parent::__construct($config);}}?>
core/View.php
<?phpnamespace core;use League\Plates\Engine;/*** 继承第三方视图 league/plates*///框架核心 视图类class View extends Engine{//不能起名叫directory, 会重写父类属性$directory;public $template; // 所渲染模板的目录// 可以传入第二个参数,指定渲染模板的文件后缀public function __construct($path,$fileExtension='html'){$this->template = parent::__construct($path);}}?>
1.MVC框架大体可分为model、view、controller,这三块主要都是类、对象的应用和扩展
2.关于composer组件是对PHP代码模块化的一种形式,代码封装,再利用;
3.MVC框架整体构架没有变化,只是在MVC的架构中添加了composer组件管理器,来方便添加组件功能;
4.对于框架可以整体理解为三部分:MVC框架部分{app和core}和组件部分{vendor和composer.json、composer.lock}以及入口文件;
5.MVC框架重点理解:命名空间和自动加载之间的关系;往往出问题都在自动加载这块,自动加载出问题:往往跟命名空间、类名称和文件路径不一致导致;注意:\和/的使用场景
(利用我们继承过来的模型catfan/medoo和视图league/plates写一个个MVC小框架)
创建的目录文件结构如下:
composer.json文件中自动加载配置项
{"name": "ldy/frame","description": "MVC小框架","require": {"catfan/medoo": "^1.7","league/plates": "^3.4"},"autoload": {"psr-4": {"app\\controllers\\": "app/controllers","app\\models\\": "app/models","app\\views\\": "app/views","core\\": "core"}}}
执行命令:composer dump-autoload
<?phpnamespace app\controllers;class UsersController{private $model=null;private $view=null;public function __construct($model,$view){$this->model = $model;$this->view = $view;}public function index(){// return __METHOD__;return $this->view->render('users/index',['name'=>'zhang']);}}?>
<?php// 业务层模型类namespace app\models;// 引入并继承核心模型文件use core\Model;class UsersModel extends Model{public function __construct(){parent::__construct();}}?>
<!DOCTYPE html><html><head><meta charset="UTF-8"><title>hello</title></head><body><h1>hello world! </h1><h2>My name is <?=$name?></h2></body></html>
<?php// composer 自动加载器require __DIR__.'\\..\\vendor\\autoload.php';use app\controllers\UsersController;use app\models\UsersModel;use core\View;// 测试业务层模型类 UsersModel// var_dump(new UsersModel);// 测试核心层 视图类 view// var_dump(new View("../../app/views"));// 测试控制器 UsersController// echo (new UsersController($model,$view))->index();$model = new UsersModel;$view= new View("../app/views");$controller = new UsersController($model,$view);echo $controller->index();?>
浏览地址:http://zhang.com/0520/zhang/public/index.php
可以通过设置网站根目录为0520/zhang/public这样预览地址:http://zhang.com/index.php
效果如下:

在入口文件中添加 .htaccess文件
<IfModule mod_rewrite.c>Options +FollowSymlinks -MultiviewsRewriteEngine OnRewriteBase /RewriteRule ^index.php$ - [L]RewriteCond %{REQUEST_FILENAME} !-fRewriteCond %{REQUEST_FILENAME} !-dRewriteRule . /index.php [L]</IfModule>
这样浏览地址中就可以省略index.php 直接通过http://zhang.com/即可访问
我们将之前用传统方式编写的动态分页案例改为MVC三层架构模式
模型层 models/StudentsModel.php
<?php// 业务层模型类namespace app\models;// 引入并继承核心模型文件use core\Model;class StudentsModel extends Model{public function __construct(){parent::__construct();}}?>
视图层 views/students/index.php
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>学生信息表</title><link rel="stylesheet" href="/static/css/style.css"></head><body><table><caption>学生信息表</caption><thead><tr><td>学号</td><td>姓名</td><td>性别</td><td>操作</td></tr></thead><tbody><?php foreach($students as $user):?><tr><td><?= $user['sno']?></td><td><?= $user['sname']?></td><td><?= $user['ssex']?></td><td><button>删除</button><button>编辑</button></td></tr><?php endforeach;?></tbody></table><?php//讨论省略点分页 前提: 两边的省略点都出现的时候//分页条显示的页数$showPages = 5;//分页条的开始页码值$startPage = 1;//分页条的结束页码值$endPage = $pages;//分页条的终止页码相对于当前页码的偏移量:$offset = ($showPages-1)/2;if($showPages < $pages){if($page > $offset+1){$startOmit = '...';$startPage = $page-$offset;$endPage = $page+$offset;if($endPage > $pages){$endPage=$pages;}}else{$startPage = 1;$endPage = $showPages;}if($showPages<$pages && $page + $offset < $pages)$endOmit = '...';}?><!-- 动态生成分页条 跳转地址 当前页码的高亮显示 --><p class="page"><!-- 首页 上一页 --><?php $prev=$page-1; if($page == 1) $prev = 1;?><a href="<?=$page != 1?'?p=1':'javascript:;'?>" style="<?=$page==1?'cursor: no-drop;':'' ?>">首页</a><a href="<?=$page != 1?'?p='.$prev:'javascript:;'?>" style="<?=$page==1?'cursor: no-drop;':'' ?>">上一页</a><?php if(isset($startOmit)):?><a href="javascript:;"><?=$startOmit?></a><?endif?><!-- 1 2 3 4 5 分页跳转页数字 --><?php for ($i=$startPage; $i <=$endPage ; $i++) :?><a class="<?=$i==$page?'active':''?>" href="<?='?p='.$i?>"><?=$i?></a><? endfor;?><?php if(isset($endOmit)):?><a href="javascript:;">...</a><?endif?><!-- 下一页 尾页 --><?php $next=$page+1; if($page == $pages) $next=$page;?><a href="<?=$page != $pages?'?p='.$next:'javascript:;'?>" style="<?=$page==$pages?'cursor: no-drop;':'' ?>">下一页</a><a href="<?=$page != $pages?'?p='.$pages:'javascript:;' ?>" style="<?=$page==$pages?'cursor: no-drop;':'' ?>">尾页</a></p></body></html>
控制层 controllers/StudentsController.php
<?phpnamespace app\controllers;class StudentsController{private $model=null;private $view=null;public function __construct($model,$view){$this->model = $model;$this->view = $view;}public function index(){$num = 5;$page = empty($_GET['p'])?1:$_GET['p'];// 获取数据$offset = ($page-1)*$num;$students = $this->model->select('student',['sno','sname','ssex'],['LIMIT'=>[$offset,$num]]);// 获取总页数$total = $this->model->count('student');$pages = ceil($total/$num);return $this->view->render('students/index',['page'=>$page,'students'=>$students,'pages'=>$pages]);}}?>
入口文件 public/index.html
<?php// composer 自动加载器require __DIR__.'\\..\\vendor\\autoload.php';use app\controllers\StudentsController;use app\models\StudentsModel;use core\View;$model = new StudentsModel;$view= new View("../app/views");$controller = new StudentsController($model,$view);echo $controller->index();?>

http://zhang.com/?p=6 这样显然不太合适,我们需要将参数改为http://zhang.com/p/6这种形式
控制器 controllers/StudentsController.php
<?phpnamespace app\controllers;class StudentsController{private $model=null;private $view=null;public function __construct($model,$view){$this->model = $model;$this->view = $view;}public function index($page=1,$num=3){// $num = 5;// 不在通过get参数?p=11这种方式使用page/11// $page = empty($_GET['p'])?1:$_GET['p'];// 获取数据$offset = ($page-1)*$num;$students = $this->model->select('student',['sno','sname','ssex'],['LIMIT'=>[$offset,$num]]);// 获取总页数$total = $this->model->count('student');$pages = ceil($total/$num);return $this->view->render('students/index',['page'=>$page,'students'=>$students,'pages'=>$pages]);}}?>
我们在视图层 views/students/index.php 中也要修改对应的翻页按钮的href属性
举个例子 (?p=1)改为(/page/1)
<a href="<?=$page!=1?'/page/1':'javascript:;'?>">首页</a><a href="<?=$page!=1?'/page/'.$prev:'javascript:;'?>">上一页</a>
入口文件 public/index.php
<?php// composer 自动加载器require __DIR__.'\\..\\vendor\\autoload.php';use app\controllers\StudentsController;use app\models\StudentsModel;use core\View;$model = new StudentsModel;$view= new View("../app/views");$controller = new StudentsController($model,$view);$params = [];if(isset($_SERVER['REDIRECT_URL'])){$res = array_values(array_filter(explode("/",$_SERVER['REDIRECT_URL'])));// $res = ['0'=>page,'1'=>3]$params[array_shift($res)] = array_shift($res);// $params = ['page'=>3];// var_dump($params);}$params['num'] = 5;print_r(call_user_func_array([$controller,'index'],$params));

启用 Apache 的 URL 重写功能, 需要开启mod_rewrite模块. 然后在服务器配置文件或.htaccess中修改服务配置:
AllowOverride allOptions FollowSysLinks
服务器配置文件和.htaccess文件中都可以配置 URL 重写. 前者是服务器级别, 后者是目录级别.
更多重写规则:https://www.jianshu.com/p/6c103e426759
在 .htaccess 文件中配置重写规则
在.htaccess文件中使用重写功能时, RewriteRule 负责匹配的 URI 是相对.htaccess所在的目录而言的.
例如访问 http://example.com/subdir1/subdir2/subdir3:
.htaccess在网站根目录下, 那么RewriteRule捕获的 URI 是subdir1/subdir2/subdir3..htaccess在 subdir1 目录下, RewriteRule捕获的 URI 是subdir2/subdir3.RewriteRule重写 URI 后的基准目录也是以.htaccess所在的目录为准. 例如: 访问 http://example.com/foo
RewriteRule ^foo$ bar.php [L]
如果.htaccess在根目录下, 重写后访问 http://example.com/bar.php. 如果在 subdir1 目录下, 重写后访问 http://example.com/subdir1/bar.php.
<IfModule mod_rewrite.c># 启用rewrite引擎RewriteEngine On# 重写规则: 匹配任意以htm后缀的文件, 将htm替换成php. ^(.*)\.htm$ 是一个正则表达式, 表示需要重写的部分, 此处指以任意字符开头, 以.htm结尾的部分. $1.php 是一个重写规则, $1 表示匹配到正则表达式中第一个子模式的字符串. [NC]: 表示重写规则如何应用, 该处表示不区分大小写. 整条规则即重写以任意字符开头, 以.htm结尾的部分, 重写为由匹配到的第一个子模式字符串和.php拼接成的字符串.RewriteRule ^(.*)\.htm$ $1.php [NC]</IfModule>
<IfModule mod_rewrite.c>RewriteEngine On# 设置目录级重写的基准URIRewriteBase /subdir1/RewriteRule ^(.*)\.htm$ $1.php [NC,L,R]</IfModule>
RewriteBase设置了重写的基准目录. 如果上例中.htaccess位于网站根目录下, 访问的 http://example.com/foo.htm, 原本重写后的基准目录是网站根目录/, 设置了RewriteBase后变为/subdir1/, 重写后实际访问 http://example.com/subdir1/foo.php.L: 表示如果可以匹配本条规则, 则不再继续往下匹配.R: 表示临时重定向, 即 302, 相当于[R=302].
<IfModule mod_rewrite.c>Options +FollowSymlinks -MultiviewsRewriteEngine OnRewriteBase /RewriteRule ^index.php$ - [L]RewriteCond %{REQUEST_FILENAME} !-fRewriteCond %{REQUEST_FILENAME} !-dRewriteRule . /index.php [L]</IfModule>
隐藏入口文件,重写后地址为http://zhang.com实际访问的地址为http://zhang.com/index.php
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号