博客列表 >PHP大牛成长之路:MVC+依赖注入+服务容器+Facade门面技术示例

PHP大牛成长之路:MVC+依赖注入+服务容器+Facade门面技术示例

周Sir-BLOG
周Sir-BLOG原创
2020年08月07日 01:01:48883浏览

1、什么是MVC?

MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写;

  • MVC简单示例:
  1. // MVC简单示例理解:
  2. //模型类: 数据库操作
  3. class Model
  4. {
  5. protected $db;
  6. // 连接数据库获取ID为1999的信息
  7. public function getData()
  8. {
  9. $this->db = new PDO('mysql:host=localhost;dbname=php_pro', 'root', 'root');
  10. return $this->db->query('select * from users where id=1999')->fetchAll(PDO::FETCH_ASSOC);
  11. }
  12. }
  13. // 视图: 数据展示(相当于HTML输出的模板)
  14. class View
  15. {
  16. public function fetch($data)
  17. {
  18. $res='hello,我叫:'.$data[0]['username'].',我今年'.$data[0]['age'].'岁了!';
  19. return $res;
  20. }
  21. }
  22. // 控制器:通常是在获取模型(Model)中数据并交给视图(View)去显示
  23. class Controller
  24. {
  25. public function index()
  26. {
  27. // 1. 获取数据
  28. $model = new Model();
  29. $data = $model->getData();
  30. // 2. 渲染模板
  31. $view = new View();
  32. return $view->fetch($data);
  33. }
  34. }
  35. // 客户端调用(测试)
  36. // 创建控制器实例/对象
  37. $controller = new Controller();
  38. echo $controller->index();

输出:hello,我叫:老周,我今年36岁了!

结论:通过简单示例,可以理解MVC各自的作用,就是用控制器(Controller)获取模型(Model)中数据并交给视图(View)去显示;

2、依赖注入

依赖注入就是用来处理类与类之间的依赖关系

比如上面 的MVC方案,控制器(Controller)中直接new()模型(Model)与视图(View)类,这种方法是最不可取的,控制器严重依赖外部的某些对象,这种现象就是大家常常听说过的: 代码的耦合度过高。

2.1 如何解决呢?—-使用:依赖注入

示例:只需要将控制器方法及客户端代码进行小修改就可以了:

  1. // 控制器:通常是在获取模型(Model)中数据并交给视图(View)去显示
  2. class Controller
  3. {
  4. //使用变量方式,以依赖注入方式解决代码的耦合度过高问题
  5. public function index($model, $view)
  6. {
  7. // 1. 获取数据
  8. $data = $model->getData();
  9. // 2. 渲染模板
  10. return $view->fetch($data);
  11. }
  12. }
  13. // 客户端调用(测试)
  14. // 创建控制器实例/对象
  15. $model = new Model();
  16. $view = new View();
  17. $controller = new Controller();
  18. //index方法传参方式(对象)->依赖注入
  19. echo $controller->index($model, $view);

2.2 上面例子以依赖注入方式解决代码的耦合度过高问题,但是如果控制器存在多个方法,可以使用构造方法实现外部对象在当前类的共享/复用

示例:只需在控制器中加入构造方法并进行小修改就可以了:

  1. // 控制器:通常是在获取模型(Model)中数据并交给视图(View)去显示
  2. class Controller
  3. {
  4. // 外部依赖的对象
  5. protected $model = null;
  6. protected $view = null;
  7. // 通过构造方法将外部对象初始化,实现了外部对象在当前类的共享/复用
  8. public function __construct($model, $view)
  9. {
  10. $this->model = $model;
  11. $this->view = $view;
  12. }
  13. //使用变量方式,以依赖注入方式解决代码的耦合度过高问题
  14. public function index()
  15. {
  16. // 1. 获取数据
  17. $data = $this->model->getData();
  18. // 2. 渲染模板
  19. return $this->view->fetch($data);
  20. }
  21. }
  22. // 客户端调用(测试)
  23. // 创建控制器实例/对象
  24. $model = new Model();
  25. $view = new View();
  26. $controller = new Controller($model, $view);
  27. echo $controller->index();

3、MVC+依赖注入+服务容器示例

使用4个文件分开进行示例:

No 文件名称 说明
1 Container.php 服务容器(Container)
2 Model.php 模型(Model)
3 View.php 视图(View)
4 Controller.php 控制器(Controller)
  • Container.php | 服务容器(Container)

将依赖的外部对象,放到一个”服务容器”中进行统一管理;

  1. namespace mvc_demo;
  2. class UsersContainer
  3. {
  4. // 1. 对象容器
  5. protected $instances = [];
  6. // 2. 绑定一个类、闭包、实例、接口实现到容器
  7. // 参数1: 是外部对象在当前对象容器数组中的键名/别名
  8. // 参数2: 是当前需要绑定到容器的对象的实例化过程(函数)
  9. public function bind($abstract, $concrete=null)
  10. {
  11. return $this->instances[$abstract] = $concrete;
  12. }
  13. // 3. 从对象容器中取出对象, 调用它
  14. public function make($abstract, $params=[] ) {
  15. return call_user_func_array($this->instances[$abstract], []);
  16. }
  17. }
  18. // 1、将外部对象: Model, View的实例绑定到服务容器中
  19. $container = new UsersContainer;
  20. // 绑定模型类实例绑定到服务容器中
  21. $container->bind('model', function(){
  22. return new Model();
  23. });
  24. // 绑定视图类实例绑定到服务容器中
  25. $container->bind('view', function(){
  26. return new View();
  27. });
  • Model.php |模型(Model)
  1. namespace mvc_demo;
  2. use PDO;
  3. // 模型类: 数据库操作
  4. class Model
  5. {
  6. protected $db;
  7. // 获取数据
  8. public function getData()
  9. {
  10. $this->db = new PDO('mysql:host=localhost;dbname=php_pro', 'root', 'root');
  11. return $this->db->query('select * from users limit 10')->fetchAll(PDO::FETCH_ASSOC);
  12. }
  13. }
  • View.php | 视图(View)
  1. namespace mvc_demo;
  2. // 视图: 数据展示
  3. class View
  4. {
  5. // 数据展示
  6. public function fetch($data)
  7. {
  8. // 表格方式展示,使用字符串拼接实现table的html代码
  9. $table = '<table>';
  10. $table .= '<caption>用户信息表</caption>';
  11. $table .= '<tr><th>ID</th><th>用户名</th><th>邮箱</th></tr>';
  12. // 遍历用户表
  13. foreach ($data as $user){
  14. $table .= '<tr>';
  15. $table .= '<td>'.$user['id'].'</td>';
  16. $table .= '<td>'.$user['name'].'</td>';
  17. $table .= '<td>'.$user['email'].'</td>';
  18. $table .= '</tr>';
  19. }
  20. $table .= '</table>';
  21. return $table;
  22. }
  23. }
  24. echo '<style>
  25. table {border-collapse: collapse; border: 1px solid;text-align: center; width: 500px;height: 150px;width: 600px;}
  26. caption {font-size: 1.2rem; margin-bottom: 10px;}
  27. tr:first-of-type { background-color:yellow;}
  28. td,th {border: 1px solid; padding:5px}
  29. </style>';
  • Controller.php | 控制器(Controller)
  1. namespace mvc_demo;
  2. //加载容器
  3. require 'Container.php';
  4. require 'Model.php';
  5. require 'View.php';
  6. class UsersController
  7. {
  8. // 获取数据,并展示出来
  9. public function index(UsersContainer $container)
  10. {
  11. // 1. 获取数据
  12. $data = $container->make('model')->getData();
  13. // 2. 渲染模板
  14. return $container->make('view')->fetch($data);
  15. }
  16. }
  17. // 客户端调用(测试)
  18. $controller = new UsersController();
  19. echo $controller->index($container);

4、MVC+依赖注入+服务容器+Facade门面技术示例

Facade门面技术: 就是将服务容器中的对象的访问进行静态接管

  • 示例3的基础上,只需要增加Facede.php及对控制器进行静态接管修改。
  1. // Facade门面技术, 静态接管服务容器中的成员的访问
  2. namespace mvc_demo;
  3. // 在服务容器与工作的控制器之间再添加一个中间层: Facade
  4. class Facade
  5. {
  6. // 服务容器
  7. protected static $container = null;
  8. // 初始化方法: 就是给当前的Facade类扣$container属性赋值
  9. // 理解为Facade的构造方法(但不是)
  10. // 将外部的服务容器注入到当前的facade中
  11. public static function initialize(UsersContainer $container)
  12. {
  13. static::$container = $container;
  14. }
  15. }
  16. // 模型类成员访问静态化(给成员套一个静态访问的马甲)
  17. class UserModel extends Facade
  18. {
  19. public static function getData()
  20. {
  21. return static::$container->make('model')->getData();
  22. }
  23. }
  24. // 视图类成员访问静态化(给成员套一个静态访问的马甲)
  25. class UserView extends Facade
  26. {
  27. public static function fetch($data)
  28. {
  29. return static::$container->make('view')->fetch($data);
  30. }
  31. }
  • 控制器进行静态接管
  1. namespace mvc_demo;
  2. //加载容器
  3. require 'Container.php';
  4. require 'Model.php';
  5. require 'View.php';
  6. require 'Facede.php';
  7. class UsersController
  8. {
  9. // 构造方法,初始化facade
  10. public function __construct(UsersContainer $container)
  11. {
  12. Facade::initialize($container);
  13. }
  14. // 用Facade方式类成员
  15. public function index()
  16. {
  17. // 1. 获取数据
  18. $data = UserModel::getData();
  19. // 2. 渲染模板
  20. return UserView::fetch($data);
  21. }
  22. }
  23. // 客户端调用(测试)
  24. $controller = new UsersController($container);
  25. echo $controller->index();

输出结果与示例3相同。

总结

  • MVC : 就是用控制器(Controller)获取模型(Model)中数据并交给视图(View)去显示;
  • 依赖注入:依赖注入就是用来处理类与类之间的依赖关系,使用变量方式,以依赖注入方式解决代码的耦合度过高问题;
  • 服务容器:将依赖的外部对象,放到一个”服务容器”中进行统一管理;
  • Facade门面技术: 就是将服务容器中的对象的访问进行静态接管。
  • Ps:大概意思理解了,但容器与Facade门面技术理解不够深入,容器的好处是什么?Facade门面技术相对于使用静态调用,加static关键字不就可以吗?
声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议