MVC服务容器门面与路由思路
相对完整的MVC框架流程
- MVC框架流程大致上是这样子的
- Model > View > Controller
- Model > View > Container > Controller
Model > View > Container > Facade > Controller
首先我们来写一个Model > View > Controller
Model模型(用来获取数据)namespace chapter6;
//模型
class Model
{
public function getData($dbname='blog',$sqlserver='mysql')
{
return (new \PDO("{$sqlserver}:".'host=localhost;dbname='."{$dbname}",'root','root'))->query('SELECT `title` FROM `art`')->fetchAll(\PDO::FETCH_ASSOC);
}
}
View视图
namespace chapter6;
//视图
class View
{
public function fetch($mdata)
{
$data = '';
$data .= '<ul>';
foreach ($mdata as $v) {
$data .= '<li>' . $v['title'] . '</li>';
}
$data .= '</ul>';
return $data;
}
}
echo "<style>
*{
margin: 0;
padding: 0;
}
li{
list-style: none;
}
ul{
max-width: 150px;
box-shadow: 0 0 5px rgba(0,0,0,0.6);
}
</style>";
控制器
namespace chapter6;
require 'Model.php';
require 'View.php';
//简单的MVC思路
class Controller
{
protected $model;
protected $view;
public function __construct(model $model, view $view)
{
$this->model = $model;
$this->view = $view;
}
public function index()
{
$data = $this->model->getData();
return $this->view->fetch($data);
}
}
//实例化
$model = new Model;
$view = new View;
//注入对象利用构造方法减少耦合
$controller = new Controller($model,$view);
echo $controller->index();
运行截图:
接下来我们来加入服务容器
PS:啥是服务容器,服务容器是干啥的?服务容器你可以理解为一个容器池,里面有你所需要使用的对象,当你需要的时候从容器里面获取对象来进行使用namespace chapter6;
//导入模型
require 'Model.php';
//导入视图
require 'View.php';
//简单的MVC思路+
//使用服务容器
class Container
{
//对象容器
protected $instances = [];
//写入对象
public function bind($alias, \Closure $process)
{
$this->instances[$alias] = $process;
}
//输出对象(也就是使用对象)
public function make($alias,$params='')
{
return call_user_func_array($this->instances[$alias],[]);
}
}
//实例化服务容器
$container = new Container;
//绑定服务对象
$container->bind('model',function (){return new Model;});
$container->bind('view',function (){return new View;});
class Controller2
{
public function index(Container $container)
{
$data = $container->make('model')->getData();
return $container->make('view')->fetch($data);
}
}
$controller = new Controller2();
echo $controller->index($container);
//使用服务容器呢就是将你需要使用的对象先放入一个对象池,然后你使用的时候从对象池中进行选取。从一定角度上是加强了控制器的灵活性,以及控制类的功能性
运行截图:
那么门面是啥?Facade门面技术可以理解为更好的使用服务容器,将服务容器内的对象进行静态化操作方便控制器进行调用(看代码就可以发现你使用了门面以后客户端所调用更为简单了)namespace chapter6;
//导入模型
require 'Model.php';
//导入视图
require 'View.php';
//简单的MVC思路++
//使用服务容器与Facade门面
//**********************服务容器 */
class Container1
{
//对象容器
protected $instances = [];
//写入对象
public function bind($alias, \Closure $process)
{
$this->instances[$alias] = $process;
}
//输出对象(也就是使用对象)
public function make($alias,$params='')
{
return call_user_func_array($this->instances[$alias],[]);
}
}
//实例化服务容器
$container = new Container1;
//绑定服务对象
$container->bind('model',function (){return new Model;});
$container->bind('view',function (){return new View;});
// **********************************************Facade门面/
//Facade门面技术可以理解为更好的使用服务容器,将服务容器内的对象进行静态化操作方便控制器进行调用
class Facade
{
//首先声明一下服务容器
protected static $container = null;
//数据
protected static $data = [];
//静态初始化
public static function initialize(Container1 $container)
{
static::$container = $container;
}
public static function getData()
{
static::$data = static::$container->make('model')->getData();
}
public static function fetch()
{
return static::$container->make('view')->fetch(static::$data);
}
}
//***************************控制器 */
class Controller3
{
public function __construct(Container1 $container)
{
Facade::initialize($container);
}
public function index()
{
//获取数据;
Facade::getData();
//渲染数据
return Facade::fetch();
}
}
$controller = new Controller3($container);
echo $controller->index();
路由思路
讲路有前我们需要先说一下一些PHP的常量
$_SERVER
- $_SERVER[‘REQUEST_URI’] 相当于获取
主机名/项目
- $_SERVER[‘SCRIPT_FILENAME’] 相当于服务器上储存的绝对路径
- $_SERVER[‘SCRIPT_NAME’] 相对当前项目上的绝对路径
- $_SERVER[‘PATH_INFO’] 并不是所有url都拥有这个值
- $_SERVER[‘QUERY_STRING’] 查询字符串
- urlencode()/urldecode()将查询字符串中的值进行编码与反编码空格会变成+;
- parse_url():解析url各部分返回一个数组
- pathinfo()返回当前脚本路径;
- parse_str()将查询字符串解析来键值对保存到一个数组中
- http_build_query()将一个关联数组解析成一个字符串查询自动转移
效果图:
当你会使用了上方的函数和常量就可以整一个简单的路由啦!
接下来我们写一个路由解析一下http://php.io/0217/ly1.php/admin/getinfo?id=10&username=xiaoyu
比如这个连接 我们可以看见入口文件时ly1.php 后面的时控制器与控制器函数admin/getinfo再后面则是字符串查询
看一下效果的样子:namespace chapter6;
//那么接下来搞一手路由的解析小案例
$url = 'http://php.io/0217/ly1.php/admin/getinfo?id=10&username=xiaoyu';
//将这个url所解析所解析
class AdminController
{
public function getInfo($id, $username)
{
return "id===>{$id}"."username==>{$username}";
}
}
//首先用PATH_INFO取出我们的PATH地址也就是我们的控制器/控制器方法
$pathinfo = explode('/',filter_input(INPUT_SERVER,'PATH_INFO'));
//array_filter过滤为空的数值
$pathinfo = array_filter($pathinfo);
//接下来由于下标错误我们用重置下标顺序
$pathinfo = array_values($pathinfo);
//接下来开始组合控制器和控制器函数
$controller = __NAMESPACE__ . '\\' . ucfirst($pathinfo[0]) . 'Controller';
$action = $pathinfo[1];
//使用QUERY_STRING 获取字符串查询
// $info = filter_input(INPUT_SERVER,'QUERY_STRING');
// var_dump($info);
//然后拆分字符串查询为数组
parse_str(filter_input(INPUT_SERVER,'QUERY_STRING'),$info);
//实例化对象
$admin = new $controller();
//callback里面可以用$admin,'getinfo'也可以我这样子写;
echo call_user_func_array([$admin,$action],$info);
我们还可以解析一下这种形式http://php.io/0217/ly2.php/admin/getinfo/id/10/name/xiaoyu
namespace chapter6;
//那么接下来搞一手路由的解析小案例
$url = 'http://php.io/0217/ly2.php/admin/getinfo/id/10/name/xiaoyu';
//将这个url所解析所解析
class AdminController1
{
public function getInfo($id, $username)
{
return "id===>{$id}"."username==>{$username}";
}
}
//首先用PATH_INFO取出我们的PATH地址也就是我们的控制器/控制器方法
$pathinfo = explode('/',filter_input(INPUT_SERVER,'PATH_INFO'));
//array_filter过滤为空的数值
$pathinfo = array_filter($pathinfo);
//接下来由于下标错误我们用重置下标顺序
$pathinfo = array_values($pathinfo);
//接下来开始组合控制器和控制器函数
$controller = __NAMESPACE__ . '\\' . ucfirst($pathinfo[0]) . 'Controller1';
$action = $pathinfo[1];
//然后我们要取出下标2以后的参数
$arraydata = array_slice($pathinfo,2);
$data = [];
for($i=0;$i<count($arraydata);$i+=2)
{
if(isset($arraydata[$i+1])){
$data[$arraydata[$i]] = $arraydata[$i+1];
}
}
//数组拆分完毕之后就可以直接开始操作
//实例化对象
$admin = new $controller();
echo call_user_func_array([$admin,$action],$data);
效果图:
提问!如果我要这样子的路由怎么解析?http://php.io/0217/ly2.php/admin/getinfo/id/10/name/xiaoyu.html
回答:很简单我们只需在PATH_INFO获取完后rtrim一手去掉.html就OK了!