在php程序设计中,应避免类严重依赖外部对象,降低”代码耦合”, 同时要”共享”依赖的外部对象,不仅如此,还应该降低程序的复杂性,使程序更加容易被访问。通过”注入依赖”、”对象共享”、”服务容器”、”Facade门面技术”等方法的使用,可以实现上述的要求。下面通过一个功能相对完整的MVC的操作来演示。
Model类
<?php
//文件src\MVC\Model.php
namespace src\MVC;
class Model
{
private $connect;
public function __construct()
{
$this->connect = new \PDO('mysql:host=localhost;dbname=phpedu', 'root', 'root');
}
public function getData(): array
{
return $this->connect->query("SELECT * FROM `{$this->table}`")->fetchAll(\PDO::FETCH_ASSOC);
}
public function __set(string $name, $val)
{
$this->{$name} = $val;
}
//查看某个字段的属性
public function getFildsInfo(\Closure $callback = NULL)
{
$stmt = $this->connect->query("SHOW full fields FROM `{$this->table}` " . (($this->fieldsnm) ? " where field='{$this->fieldsnm}';" : NULL));
$fetch = $stmt->fetchAll(\PDO::FETCH_ASSOC);
if (!isset($this->property)) {
return $fetch[0];
}
$res = $fetch[0][$this->property];
if (!$callback) {
return $res;
} else {
return call_user_func_array($callback, [$res]);
}
}
//将备注属性进行替换,备注用query_string的格式书写"性别?0=男&1=女"
public function getProperty($name = NULL)
{
return $this->getFildsInfo(function ($str) use ($name) {
$info = \parse_url($str);
//如果没有query
if ($name === NULL) return $info['path'];
//如果有query
if (isset($info['query'])) {
\parse_str($info['query'], $params);
return $params[$name];
}
});
}
}
View类
<?php
//文件src\MVC\View.php
namespace src\MVC;
class View
{
private $model;
public function __construct(Model $model)
{
$this->model = $model;
}
public function __set(string $name, $val)
{
$this->{$name} = $val;
}
public function fetch()
{
//处理表头
$replacestr = function ($fieldsnm, $property, $value = NULL) {
$this->model->fieldsnm = $fieldsnm;
$this->model->property = $property;
$res = $this->model->getProperty($value);
return (strlen(str_replace(' ', '', $res)) === 0) ? $fieldsnm : $res;
};
$fieldsPro = function ($fieldValue, $field) {
//处理时间戳
if (isset($this->model->timestamp) && in_array($field, $this->model->timestamp)) {
return date('Y年m月d日', $fieldValue);
};
//处理元素备注
if (isset($this->model->default) && in_array($field, $this->model->default)) {
$this->model->fieldsnm = $field;
$this->model->property = 'Comment';
return $this->model->getProperty($fieldValue);
};
return $fieldValue;
};
//样式
$css = <<<DOC
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="{$this->css}" type="text/css"/>
<title>Document</title>
</head>
<body>
DOC;
//数据
$data = $this->model->getData();
//字段
$fields = array_keys($data[0]);
//css样式表
$table .= $css;
$table .= '<table>';
//标题
$table .= '<caption>' . $this->title . '</caption>';
//表头
$table .= '<tr>';
foreach ($fields as $value) {
$table .= '<th>' . $replacestr($value, 'Comment') . '</th>';
}
$table .= '</tr>';
//主体
foreach ($data as $value) {
$table .= '<tr>';
foreach ($fields as $field) {
$table .= '<td>' . $fieldsPro($value[$field], $field) . '</td>';
}
$table .= '</tr>';
}
//结束标志
$table .= '</table>';
$table .= '</body>';
$table .= '</html>';
return $table;
}
}
View类用到的css文件
/*文件src\MVC\css.css*/
table {border-collapse: collapse; border: 1px solid;text-align: center;}
caption {font-size: 1.2rem; margin-bottom: 10px;}
tr:first-of-type { background-color:wheat;}
td,th {border: 1px solid; padding:5px}
Container对象容器
<?php
//文件 src\MVC\Container.php
namespace src\MVC;
//对象容器
class Container
{
protected $container=[];
public function bind(string $name, \Closure $closure)
{
$this->container[$name]=$closure;
}
public function make(string $name, $params=[])
{
return call_user_func_array($this->container[$name], $params);
}
}
Facade门面类
<?php
//文件 src\MVC\Facade.php
namespace src\MVC;
//Facade门面类
class Facade
{
protected static $container;
protected static $model;
public static function initialize(Container $container)
{
static::$container=$container;
}
public static function getData()
{
static::$model=static::$container->make('model');
static::$model->getData();
}
public static function fetch()
{
return static::$container->make('view',[static::$model])->fetch();
}
}
Controller 控制器
<?php
//文件src\MVC\Controller.php
namespace src\MVC;
//控制器
class Controller
{
public function __construct(Container $container)
{
Facade::initialize($container);
}
public function index()
{
//model
Facade::getData();
//view
return Facade::fetch();
}
}
自动加载类
<?php
//文件src\MVC\AutoLoad.php
namespace src\MVC;
spl_autoload_register(function($class)
{
$prefix=__DIR__;
$arr=explode("\\",$class);
$file=$prefix."\\". $arr[count($arr)-1] . '.php';
$file = str_replace("\\", DIRECTORY_SEPARATOR, $file);
file_exists($file) ? require $file : "文件不存在,加载失败";
});
调用类
<?php
//文件src\MVC\Main.php
namespace src\MVC;
//自动加载
require 'AutoLoad.php';
$container=new Container();
$container->bind('model',function(){
$model= new Model();
$model->table='staffs';
//timestamp可添加时间字段集
$model->timestamp=['register_time','hiredate'];
//default可添加需解析备注Comment的字段集
$model->default=['sex'];
return $model;
});
$container->bind('view',function(Model $model){
$view= new View($model);
$view->title="人员信息表";
$view->css='css.css';
return $view;
});
$control=new Controller($container);
echo $control->index();
结果
1. 使用的数据表staffs
、users
结构和内容
2. 运行结果
总结
Facade门面:是一种通过为多个复杂的子系统提供一个一致的接口,而使这些子系统更加容易被访问的模式。该模式对外有一个统一接口,外部应用程序不用关心内部子系统的具体的细节,这样会大大降低应用程序的复杂度,提高了程序的可维护性。