批改状态:合格
老师批语:正解的非常透彻, 不少工作几年的程序员, 都不一定有你的高度, 不错
MVC的主要思想
(model模型、view视图、controller控制 - 程序员主要是在折腾控制)
三种主要设计模式:
a-“依赖注入”,通过class去构建Model、view,然后通过controller去控制
b- 服务容器:将对外部的依赖放到容器中,让依赖更加简单、抽象。
c- Facade门面技术:在服务容器和控制器之间生成一个静态过渡类,让后续的控制器访问进一步抽象。
《盗梦空间》—— 不得不服老外在编程技术上的积累和精进。国内还有太多路要走。
后面的层层嵌套、深入,类似《盗梦空间》,开始觉得还精巧,到后面把握不住火候的话,就感觉玩大了,兜不住了 —— 这个时候就需要不断地提升认知。
每一层class的延伸,包括facade门面技术,都类似从一层梦境进入另外一层梦境。越来越抽象,越来越牵一发而动全身。
<?php// -----模型部分: 当前页面要显示的数据$pdo = new PDO('mysql:host=localhost;dbname=phpedu', 'root', 'root');$users = $pdo->query('select * from users limit 10')->fetchAll(PDO::FETCH_ASSOC);?><!-- 视图部分 --><!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>用户列表</title></head><body><table border="1" width="60%"><caption>用户表</caption><tr><th>id</th><th>name</th><th>email</th></tr><?php foreach ($users as $user): ?><tr><td><?=$user['id']?></td><td><?=$user['name']?></td><td><?=$user['email']?></td></tr><?php endforeach ?></table></body></html>
不同的项目切入点不同。
几种设计模式
① 依赖注入
② 服务容器
③ Facade
<?phpnamespace mvc_demo;use PDO;// 模型类: 数据库操作class Model{// 获取数据public function getData(){return (new PDO('mysql:host=localhost;dbname=phpedu', 'root', 'root'))->query('select * from users limit 10')->fetchAll(PDO::FETCH_ASSOC);// 通过链式方式得到数据}}// 测试模型// print_r((new Model)->getData());
<?phpnamespace mvc_demo;// 视图: 数据展示class View{// 数据展示public function fetch($data){// 表格方式展示,使用字符串拼接实现table的html代码// $table .= 相当于 $table = $table. + ...用来拼接语句)$table = '<table>';$table .= '<caption>用户信息表</caption>';$table .= '<tr><th>ID</th><th>用户名</th><th>邮箱</th></tr>';// 遍历用户表foreach ($data as $user){$table .= '<tr>';$table .= '<td>'.$user['id'].'</td>';$table .= '<td>'.$user['name'].'</td>';$table .= '<td>'.$user['email'].'</td>';$table .= '</tr>';}$table .= '</table>';//这块的table跟之前有一些区别,去掉了php等标识,可以了解下。return $table;}}echo '<style>table {border-collapse: collapse; border: 1px solid;text-align: center; width: 500px;height: 150px;width: 600px;}caption {font-size: 1.2rem; margin-bottom: 10px;}tr:first-of-type { background-color:yellow;}td,th {border: 1px solid; padding:5px}</style>';// 视图测试// require 'Model.php';// echo (new View)->fetch((new Model)->getData());
<?php// 控制器1namespace mvc_demo;// 加载模型类require 'Model.php';// 加载视图类require 'View.php';class Controller1{// 获取数据,并展示出来public function index(){// 1. 获取数据$model = new Model();$data = $model->getData();// 2. 渲染模板$view = new View();return $view->fetch($data);}}// 客户端调用(测试)// 创建控制器实例/对象$controller = new Controller1();echo $controller->index();//
<?php// 控制器2: 使用依赖注入解决类/对象之间的耦合度过高的问题namespace mvc_demo;// 加载模型类require 'Model.php';// 加载视图类require 'View.php';class Controller2{// 获取数据,并展示出来public function index($model, $view){// 1. 获取数据$data = $model->getData();// 2. 渲染模板(也就是数据展示)return $view->fetch($data);}/* 问题又来了: 控制器依赖的外部对象,尽管已经通过依赖注入进行了当前类中,但是没有办法实现外部对象的复用。例如下面调用的时候又需要重新new?*/public function edit($model){}}// 客户端调用(测试)// 创建控制器实例/对象$model = new Model();$view = new View();$controller = new Controller2();echo $controller->index($model, $view);$controller->edit($model);
<?php// 控制器3: 实现外部依赖注入的对象在类内部的共享/复用namespace mvc_demo;// 加载模型类require 'Model.php';// 加载视图类require 'View.php';class Controller3{// 外部依赖的对象private $model = null;//后面的null也可以不写private $view = null;// 通过构造方法将外部对象初始化,实现了外部对象在当前类的共享/复用public function __construct($model, $view){$this->model = $model;$this->view = $view;}// 获取数据,并展示出来public function index(){// 1. 获取数据$data = $this->model->getData();// 2. 渲染模板return $this->view->fetch($data);}// 外部对象的复用public function edit(){// $this->model;}}// 客户端调用(测试)// 创建控制器实例/对象$model = new Model();$view = new View();// 将外部对象的注入点从普通方法,改到了构造方法中$controller = new Controller3($model, $view);echo $controller->index();//之前的参数是方法级别的,现在则提升到了类级别。$controller->edit();// o:这种情况下class内的每个方法就要相对简单,因为无法在括号中传参。// 当然也有可能方法本身就应该相对简单,一个方法一个非常独立的返回。当然这默认所有的类中的参数方法都是可以使用的了。
<?php// 控制器4: 将当前依赖的外部对象,放到一个"服务容器"中进行统一管理namespace mvc_demo;use Closure; // 后面使用闭包类型的时候前面就不用加/了。// 加载模型类require 'Model.php';// 加载视图类require 'View.php';// -----------------------------------------// 服务容器class Container1{// 1. 对象容器protected $instances = [];// 2. 向对象容器中添加对象// 参数1: 是外部对象在当前对象容器数组中的键名/别名// 参数2: 是当前需要绑定到容器的对象的实例化过程(函数)public function bind($alias, Closure $process)//第二个参数是一个函数,使用闭包类型{$this->instances[$alias] = $process;}// 3. 从对象容器中取出对象, 调用它public function make($alias, $params=[] ) {return call_user_func_array($this->instances[$alias], []);}}// 将外部对象: Model, View的实例绑定到服务容器中$container = new Container1;// 绑定模型类实例绑定到服务容器中$container->bind('model', function(){return new Model();});// 绑定视图类实例绑定到服务容器中$container->bind('view', function(){return new View();});// ------------------------------------------class Controller4{// 获取数据,并展示出来public function index(Container1 $container){// 1. 获取数据$data = $container->make('model')->getData();// 2. 渲染模板return $container->make('view')->fetch($data);}}// 客户端调用(测试)$controller = new Controller4();echo $controller->index($container);// 为什么要用服务容器?// 将当前类对许多外部对象的依赖, 转为对一个服务容器的依赖// 将外部对象的依赖,使用服务容器进行了接管// 这样下来后面的地方就简化了很多。
<?php// 控制器5: Facade门面技术, 静态接管服务容器中的成员的访问namespace mvc_demo;use Closure;require 'Model.php';require 'View.php';// -----------------------------------------// 服务容器class Container2{// 1. 对象容器protected $instances = [];public function bind($alias, Closure $process){$this->instances[$alias] = $process;}// 3. 从对象容器中取出对象, 调用它public function make($alias, $params=[] ) {return call_user_func_array($this->instances[$alias], []);}}// 将外部对象: Model, View的实例绑定到服务容器中$container = new Container2;// 绑定模型类实例绑定到服务容器中$container->bind('model', function(){return new Model();});// 绑定视图类实例绑定到服务容器中$container->bind('view', function(){return new View();});// ------------------------------------------// 在服务容器与工作的控制器之间再添加一个中间层: Facadeclass Facade{// 服务容器protected static $container = null;// 初始化方法: 就是给当前的Facade类中的$container属性赋值// 理解为Facade的构造方法(但不是)// 将外部的服务容器注入到当前的facade中public static function initialize(Container2 $container){static::$container = $container;// 给本类中的静态属性赋值,其实就是将前面的容器初始化。}}// 模型类成员访问静态化(给成员套一个静态访问的马甲)class UserModel extends Facade{public static function getData(){return static::$container->make('model')->getData();}}// 视图类成员访问静态化(给成员套一个静态访问的马甲)class UserView extends Facade{public static function fetch($data){return static::$container->make('view')->fetch($data);}}// ------------------------------------------class Controller5{// 构造方法,初始化facadepublic function __construct(Container2 $container){Facade::initialize($container);}// 用Facade方式类成员public function index(){// 1. 获取数据$data = UserModel::getData();// 2. 渲染模板return UserView::fetch($data);}}// 客户端调用(测试)$controller = new Controller5($container);echo $controller->index();
<?phpnamespace mvc;use PDO;class dataModel{public function gettData(){return (new PDO('mysql:host=localhost;dbname=liangtest','liang','123456'))->query('SELECT * FROM `shao` LIMIT 8')->fetchAll(PDO::FETCH_ASSOC);}}print_r((new dataModel)->gettData());/*8月4日作业1. 将课堂视频至少看二遍以上,细细品服务容器与facade带来的好处,并写出自己的总结2. 试着用mvc实现一个简单的业务逻辑(可仿课堂案例,但不要全照抄)3. 可选: 如何优化Facade的调用过程*/
<?phpnamespace mvc;class shaoView{public function fetch($items){$table = '<table>';$table .= '<caption>内容列表</caption>';$table .= '<tr><th>id</th><th>date</th><th>title</th><th>tags</th></tr>';foreach ($items as $item){$table .= '<tr>';$table .= '<td>'.$item['id'].'</td>';$table .= '<td>'.$item['date'].'</td>';$table .= '<td>'.$item['title'].'</td>';$table .= '<td>'.$item['label'].'</td>';$table .= '</tr>';}$table .= '/<table>';return $table;}}echo '<style>table {border-collapse: collapse; border: 1px solid;text-align: center; width: 500px;height: 150px;width: 600px;}caption {font-size: 1.2rem; margin-bottom: 10px;}tr:first-of-type { background-color:yellow;}td,th {border: 1px solid; padding:5px}</style>';require 'z1model.php';echo (new shaoView)->fetch((new dataModel)->gettData());
<?phpnamespace mvc;use Closure;require 'z2view.php';class objContainer{protected $insts = [];public function bind($name, Closure $process){$this->insts[$name] = $process;}public function make($name,$params=[]){return call_user_func_array($this->insts[$name],[]);}}$container = new objContainer;$container->bind('dataModel',function(){return new dataModel();});$container->bind('shaoView',function(){return new shaoView();});class Facade{protected static $container =null;public static function initialize(objContainer $container){static::$container = $container;}}class dataamodel extends Facade{public static function gettData(){return static::$container->make('dataModel')->gettData();}}class shaooView extends Facade{public static function fetch($data){return static::$container->make('shaoView')->fetch($data);}}class Controller{public function __construct(objContainer $container){Facade::initialize($container);}public function index(){$data = dataamodel::gettData();return shaooView::fetch($data);}}$controller = new Controller($container);echo $controller->index();
最终比较幸运,数据都能读取出来。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号