PHP:MVC之间的关系 ,容器与依赖注入,facade门面技术
MVC (一种架构模式)
- M: Model(模型层),最bottom一层,是核心数据层,程序需要操作的数据或信息.
- V:View (视图层),最top一层,直接面向最终用户,视图层提供操作页面给用户,被誉为程序的外壳.
C: Controller(控制层),是middile层, 它负责根据用户从”视图层”输入的指令,选取”数据层”中的数据,然后对其进行相应的操作,产生最终结果。
仿站: V - M - C
- 自主: M - V - C
设计模式
- 依赖注入
- 服务容器Container
- Facade
- 单例模式(把构造方法私有化) 防止重复实例化,避免大量的new操作,减少消耗系统和内存的资源,使得有且仅有一个实例对象
依赖注入
容器和依赖注入
ThinkPHP使用容器来更方便的管理类依赖及运行依赖注入,新版的容器支持PSR-11规范。容器类的工作由think\Container类完成,但大多数情况我们只需要通过app助手函数或者think\App类即可容器操作,如果在服务类中可以直接调用this->app进行容器操作。
依赖注入其实本质上是指对类的依赖通过构造器完成自动注入,例如在控制器架构方法和操作方法中一旦对参数进行对象类型约束则会自动触发依赖注入,由于访问控制器的参数都来自于URL请求,普通变量就是通过参数绑定自动获取,对象变量则是通过依赖注入生成。
依赖注入的对象参数支持多个,并且和顺序无关。
支持使用依赖注入的场景包括(但不限于):
- 控制器架构方法;
- 控制器操作方法;
- 路由的闭包定义;
- 事件类的执行方法;
- 中间件的执行方法;
一.Model:模型层
- 模型层获取数据表中数据
代码块
<?php
namespace my_Model;
use PDO;
//模型层 获取数据表中数据
class Model
{
public function getData()
{
return (new PDO('mysql:host=localhost;dbname=zwz','zwz1230','a123456'))->query("SELECT `id`,`uname` FROM `user` ORDER BY `id` asc LIMIT 10")->fetchAll(PDO::FETCH_ASSOC);
}
}
print_r((new Model())->getData());
二.View:视图层
- 视图层 生成可视化表格
代码块
<?php
namespace my_Model;
//视图层 生成可视化表格
class View
{
public function fetch($data)
{
$table = '<table>';
$table.= '<caption>用户信息表</caption>';
$table.= '<tr><th>编号</th><th>姓名</th></tr>';
foreach ($data as $key => $user) {
$table.= '<tr>';
$table.= '<td>'.$user['id'].'</td>';
$table.= '<td>'.$user['uname'].'</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:lightblue;}
td,th {border: 1px solid; padding:5px}
</style>';
三.Controller:控制层
- 中间桥梁 控制器
代码块
<?php
namespace my_Model;
require 'Model.php';
require 'View.php';
//中间桥梁 控制器
class Controller
{
//依赖注入外部对象
public function index(Model $Model,View $View)
{
//1.获取数据
$data = $Model->getData();
//2.模板渲染
return $View->fetch($data);
}
}
$model = new Model() ;
$view = new View();
$controller = new Controller($model,$view);
echo $controller->index($model,$view);
四.使用依赖注入的方式进行传参
- 依赖注入要使用到构造器
__construct()
,可以在类方法中共享方法
代码块
<?php
namespace my_Model;
require 'Model.php';
require 'View.php';
//中间桥梁 控制器
class Controller
{
protected $Model;
protected $View;
//依赖注入 使用构造器进行传参可以在类方法中共享
public function __construct(Model $Model,View $View)
{
$this->Model = $Model;
$this->View = $View;
}
public function index(Model $Model,View $View)
{
$data = $this->Model->getData();
return $this->View->fetch($data);
}
}
$model = new Model() ;
$view = new View();
$controller = new Controller($model,$view);
//采用异步回调方式进行输出
echo call_user_func_array([$controller,"index"],[$model,$view]);
五.容器与facade门面技术
①服务容器
绑定
- 依赖注入的类统一由容器进行管理,大多数情况下是在自动绑定并且实例化的。不过你可以随时进行手动绑定类到容器中(通常是在服务类的register方法中进行绑定),支持多种绑定方式。
容器:container :依赖注入的类统一由容器进行管理,容器 数组
- 如果当前类依赖的对象很多, 可以将这些依赖的对象 , 类,闭包,放到一个”服务容器”中进行统一管理 绑定:bind 取出:make
Container 容器代码块
<?php
namespace my_Model;
/**
* 容器:container :依赖注入的类统一由容器进行管理,容器 数组
*
* 如果当前类依赖的对象很多, 可以将这些依赖的对象 , 类,闭包,放到一个"服务容器"中进行统一管理 bind make
*/
use Closure;
require 'Model.php';
require 'View.php';
//服务容器 : 一个自动生产类/对象的工厂
class Container
{
//1.对象容器 数组
protected $instances = [];
/**
* 2.往对象容器数组中去绑定 对象
* 绑定一个类、闭包、实例、接口实现到容器
* @access public
* @param string|array $abstract 类标识、接口的别名 alias
* @param mixed $concrete 要绑定的类、闭包或者实例
* @return $this
*/
public function bind($abstract,Closure $concrete)
{
//初始化对象容器,健是别名,键值是对象
$this->instances[$abstract] = $concrete;
}
//3. 从对象容器中取出 对象并调用
public function make($abstract,$params=[])
{
return call_user_func_array($this->instances[$abstract],$params);
}
}
$container = new Container;
//绑定一个闭包到容器 : 我们使用这个model对象的时候 再去实例化
$container->bind('model',function(){
return new Model();
});
$container->bind('view',function(){
return new View();
});
class Controller
{
public function index(Container $container)
{
$data = $container->make('model')->getData();
return $container->make('view')->fetch($data);
}
}
//客户端代码
$contrl = new Controller;
echo $contrl->index($container);
②facade门面技术
- 门面(Facade)
- 门面为容器中的(动态)类提供了一个静态调用接口,相比于传统的静态方法调用, 带来了更好的可测试性和扩展性,你可以为任何的非静态类库定义一个facade类。
facade 门面技术 实现类成员访问静态化
facade代码块
// facade 门面技术
class Facade {
//为容器中的类提供一种静态调用方式
protected static $container;
public static function initialize(Container $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 Controller
{
public function __construct(Container $container)
{
Facade::initialize($container);
}
public function index()
{
$data = UserModel::getData();
return UserView::fetch($data);
}
}
//客户端代码
echo (new Controller($container))->index();