- 在代码越来越多,各种功能创建之后,就需要进行分层分类管理。依赖关系清晰,才能使程序有更好的维护性。
1.MVC框架
- 分别建立模型类型、控制器类和视图类
- 在控制器中调用模型获取数据,然后调用视图类输出数据展示
1.1 Model类
- 该模型类功能主要是查询数据,所以直接继承Db数据库操作类
Model.php
<?php
namespace home;
require 'Db.php';
class Model extends Db
{
}
Db.php
<?php
namespace home;
//数据库操作类
class Db{
public static $link = null;//保存pdo连接
public static $sql = null;//保存语句
//使用构造函数连接数据库
public function __construct($dsn,$username,$password){
try{
self::$link = new \PDO($dsn,$username,$password);
if(empty(self::$link)){
echo '数据库连接失败';
}
}catch(\Exception $e){
echo $e->getMessage();
}
}
//新增数据
public static function add(string $table,array $data){
$val = array_values($data);
$keys = array_map(function($item){
return $item = '`'.$item.'`=?';
},array_keys($data));
$fields = implode(",",$keys);
//预处理sql语句,使用占位符
$sql = "insert {$table} set {$fields}";
$stmt = self::$link->prepare($sql);
//执行查询语句
$stmt->execute($val);
if($stmt->rowCount()===1){
return self::$link->lastInsertId();//获取新增的主键ID
}else{
return $stmt->errorInfo();
}
}
//查询数据
public static function find(string $sql){
//预处理sql语句
$stmt = self::$link->prepare($sql);
//执行查询语句
$stmt->execute();
return $stmt->fetchAll(\PDO::FETCH_ASSOC);
}
//更新数据
public static function update(string $table,string $where,array $data)
{
$val = array_values($data);
$keys = array_map(function($item){
return $item = '`'.$item.'`=?';
},array_keys($data));
$fields = implode(",",$keys);
//预处理sql语句,使用占位符
self::$sql = "update `{$table}` SET {$fields} {$where}";
$stmt = self::$link->prepare(self::$sql);
//执行查询语句
$stmt->execute($val);
if($stmt->rowCount()){
return $stmt->rowCount();//返回受影响的记录数
}else{
return $stmt->errorInfo();
}
}
//删除数据
public static function delete($table,$where)
{
$sql = "DELETE FROM `{$table}` {$where}";
self::$sql=$sql;
$stmt = self::$link->prepare($sql);
$stmt->execute();
if($stmt->rowCount()){
return $stmt->rowCount();//返回受影响的记录数
}else{
return $stmt->errorInfo();
}
}
}
1.2 View类
- 把数据在goods.php模板文件中展示
<?php
namespace home;
class View
{
public function fetch($data){
include 'goods.php';
}
}
goods.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>商品信息维护</title>
<style>
body {
display: flex;
flex-flow: column nowrap;
align-items: center;
}
form {
display: flex;
flex-flow: row wrap;
}
form>section {
margin: 10px;
display: flex;
flex-flow: row nowrap;
}
table {
margin-top: 30px;
width: 1000px;
font-family: verdana, arial, sans-serif;
font-size: 11px;
color: #333333;
border-width: 1px;
border-color: #666666;
border-collapse: collapse;
}
table>thead {
background-color: #80ff80;
}
table th {
border-width: 1px;
padding: 8px;
border-style: solid;
border-color: #666666;
}
table td {
border-width: 1px;
padding: 8px;
border-style: solid;
border-color: #666666;
background-color: #ffffff;
text-align: center;
}
tfoot>tr,
tfoot>tr>td {
width: initial;
}
</style>
</head>
<body>
<hr>
<hr>
<form action="<?php echo $_SERVER['PHP_SELF'] ?>" class="queryterms" method="POST">
<section>
<label for="goodsname">商品名称:</label>
<input type="text" name="goodsname" id="goodsname"
value="<?php if(isset($_SESSION['goodsname'])) echo $_SESSION['goodsname']?>">
</section>
<section>
<label for="goodsmodel">商品型号:</label>
<input type="text" name="goodsmodel" id="goodsmodel"
value="<?php if(isset($_SESSION['goodsmodel'])) echo $_SESSION['goodsmodel']?>">
</section>
<section>
<button>查询</button>
</section>
</form>
<div>
<table>
<thead>
<tr>
<th>ID</th>
<th>名称</th>
<th>型号</th>
<th>价格</th>
<th>数量</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<?php foreach($data as $val):?>
<tr>
<td><?php echo $val['id'] ?></td>
<td><?php echo $val['name']?></td>
<td><?php echo $val['model']?></td>
<td><?php echo $val['price']?></td>
<td><?php echo $val['number']?></td>
<td><?php echo $val['status']?></td>
<td><a href="handle.php?act=edit&id=<?php echo $val['id'] ?>">编辑</a>
<a href="handle.php?act=delete&id=<?php echo $val['id'] ?>">删除</a></td>
</tr>
<?php endforeach; ?>
</tbody>
<tfoot>
<tr>
<td colspan="7"><?php if(isset($page))echo $page; ?></td>
</tr>
</tfoot>
</table>
</div>
</body>
</html>
1.3 Controller类
- 在Controller中实例化model和view类
- 然后调用find方法获取数据,调用fetch方法展示数据
<?php
namespace home;
require 'Model.php';
require 'View.php';
//.直接在方法内实例化外部类使用
class Controller
{
public function index($dsn,$username,$password){
$data = (new Model($dsn,$username,$password))::find('select * from goods limit 2');
return (new View)->fetch($data);
}
}
$ctrl = new Controller;
$ctrl->index($dsn,$username,$password);
至此,就完成了一个最简单的mvc框架,Model类负责处理数据、view输出展示数据,controller类负责接收处理请求和返回数据
效果图:
2. 容器
- 以上mvc框架中的congtroller在类中直接实例化外部类,对外部类依赖性很强,代码耦合度高,如Model类的参数发生变化,congtroller类中也需要同步修改.
- 如Model类中重写构造方法为不传参,而是引入文件,以上的congtroller类就需要修改
<?php
namespace home;
require 'Db.php';
class Model extends Db
{
public function __construct(){
if(file_exists('config.php')){
include 'config.php';
}
try{
self::$link = new \PDO($dsn,$username,$password);
if(empty(self::$link)){
echo '数据库连接失败';
}
}catch(\Exception $e){
echo $e->getMessage();
}
}
}
2.1 参数依赖
- 在此,我们可以通过参数方式传递外部类的实例来解耦
// 在参数中传入外部类的实例
class Controller
{
public function index(Model $model,view $view){
$data = $model::find('select * from goods limit 2,3');
return $view->fetch($data);
}
}
$ctrl = new Controller;
$ctrl->index(new Model,new View);
效果图:
通过参数传递类实例的方式,成功把模型和视图类的实例创建放到了客户端,代码涉及改造量也大大降低。但是依赖的类很多时,要一个个的创建类的实例,也比较麻烦
2.2 服务容器
- 为解决以上问题,我们可以创建一个容器,把所有类的实例化步骤都放到该容器中,使用时直接用该类的别名即可获得该类的实例。
- 在容器类中有两个方法,一是绑定,将类在容器中注册服务;一是取出,根据注册的类的别名获取类的实例
服务容器:
<?php
namespace home;
//服务容器类
class Container
{
public $binds = [];
//绑定服务到容器
public function bind($alias,\Closure $process){
$this->binds[$alias] = $process;
}
//使用
public function make($alias,array $param=[]){
return call_user_func_array($this->binds[$alias],$param);
}
}
容器依赖:
class Controller3
{
public function index(Container $container){
//从容器中取得model和view类的对象实例
$data = $container->make('Model')::find('select * from goods limit 6,5');
return $container->make('View')->fetch($data);
}
}
$container = new Container;
//注册服务,绑定类到容器中
$container->bind('Model',function(){return new Model();});
$container->bind('View',function(){return new View;});
$container->bind('controller',function(){return new Controller3;});
//使用服务
$container->make('controller')->index($container);
效果图:
服务容器就像一个全局变量,把所有服务类放到容器中,使用时根据注册的名字即可直接获得实例