php开源一个mvc框架的诞生之路由实现
Posted OpenFramework
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了php开源一个mvc框架的诞生之路由实现相关的知识,希望对你有一定的参考价值。
一个有效的浏览器请求是:
用户电脑端打开浏览器—>输入网址请求—>服务端接受浏览器请求—>然后处理好逻辑返回给浏览器—>浏览器根据载入的资源渲染在窗口上给用户展示。
开发路由需要制定一系列规则,以便更好的响应请求。
class Router
{
/**
* @param array $rule
* 路由规则
*/
private $rule = [];
/**
* @param string $url_module
* url模式
* URL模式 0普通模式 1 pathinfo模式 2 rewrite模式
*/
private $url_module = '1';
/**
* @param array $url
* 封装后请求地址
*/
private $url = [];
/**
* @param array $path
* 请求地址
*/
private $path;
/**
* @param string $default_platform
* 默认操作平台
*/
private $default_platform = 'main';
/**
* @param string $default_controller
* 默认控制器
*/
private $default_controller = 'Home';
/**
* @param string $default_action
* 默认操作方法
*/
private $default_action = 'main';
/**
* @param string $var_platform
* 默认模块传参变量
*/
private $var_platform = 'm';
/**
* @param string $var_controller
* 默认控制器传参变量
*/
private $var_controller = 'c';
/**
* @param string $var_action
* 默认方法传参变量
*/
private $var_action = 'a';
/**
* @param bool $route_rules_on
* 是否开启路由自定义配置
*/
private $route_rules_on = true;
/**
* @param string $get_param
* get参数
*/
private $get_param;
private $platform;
private $controller;
private $action;
private $dir = APPLICATION_PATH;
private $namespace = APP_NAMESPACE_NAME;
public function run(Router $router){}
public function import($rules)
{
if(is_array($rules)){
foreach($rules as $tag => $rule){
$this->addRule($rule);
}
}
return $this;
}
public function addRule($rule)
{
if($rule instanceof Closure){
$ruleClosure[] = $rule;
$this->rule = array_merge($this->rule,$ruleClosure);
}
$this->rule = array_merge($this->rule,$rule);
return $this;
}
public function parser()
{
(new Parser())->parserPath($this);
return $this;
}
public function dispatch()
{
(new Dispatch())->dispatch($this);
return $this;
}
public function setUrlModel($model)
{
$this->url_module = $model;
return $this;
}
public function setUrl($url)
{
$this->url = $url;
return $this;
}
public function setPath($path)
{
$this->path = $path;
return $this;
}
public function setDefaultPlatform($platform)
{
$this->default_platform = $platform;
return $this;
}
public function setDefaultController($controller)
{
$this->default_controller = $controller;
return $this;
}
public function setDefaultAction($action)
{
$this->default_action = $action;
return $this;
}
public function setVarPlatform($platform)
{
$this->var_platform = $platform;
return $this;
}
public function setVarController($controller)
{
$this->var_controller = $controller;
return $this;
}
public function setVarAction($action)
{
$this->var_action = $action;
return $this;
}
public function setRouterOn($bool)
{
$this->route_rules_on = $bool;
return $this;
}
public function setGetParam($param)
{
$this->get_param = $param;
return $this;
}
public function setPlatform($platform)
{
$this->platform = $platform;
return $this;
}
public function setController($controller)
{
$this->controller = $controller;
return $this;
}
public function setAction($action)
{
$this->action = $action;
return $this;
}
public function setDir($dir)
{
$this->dir = $dir;
return $this;
}
public function setNamespace($namespace)
{
$this->namespace = $namespace;
return $this;
}
/////////////////参数获取//////////////////////
public function getUrlModel()
{
return $this->url_module;
}
public function getUrl($key='')
{
return $key == '' ? $this->url : $this->url[$key];
}
public function getPath()
{
return $this->path;
}
public function getDefaultPlatform()
{
return $this->default_platform;
}
public function getDefaultController()
{
return $this->default_controller;
}
public function getDefaultAction()
{
return $this->default_action;
}
public function getVarPlatform()
{
return $this->var_platform;
}
public function getVarController()
{
return $this->var_controller;
}
public function getVarAction()
{
return $this->var_action;
}
public function getRouterOn()
{
return $this->route_rules_on;
}
public function getRule()
{
return $this->rule;
}
public function getGetParam()
{
return $this->get_param;
}
public function getPlatform()
{
return $this->platform;
}
public function getController()
{
return $this->controller;
}
public function getAction()
{
return $this->action;
}
public function getDir()
{
return $this->dir;
}
public function getNamespace()
{
return $this->namespace;
}
}
初始化路由类通过import方法导入路由规则配置文件,然后设置相关路由配置,最后执行路由解析器
parser
方法
最后执行路由分发
dispatch
方法
使用方法案例:
Application::router()
->import(LOAD_PATH . 'router.php')
->setUrlModel('1')
->setPath('')
->setDefaultPlatform('main')
->setDefaultController('Home')
->setDefaultAction('main')
->setVarPlatform('m')
->setVarController('c')
->setVarAction('a')
->setRouterOn('true')
->setGetParam(Application::input('get.'))
->setPlatform('')
->setController('')
->setAction('')
->setDir(APPLICATION_PATH)
->setNamespace(APP_NAMESPACE_NAME)
->parser()
->dispatch()
完整的路由设置启动分发,具体的方法router类有注释
class Parser
{
private $_router;
public function parserPath(Router $router)
{
$this->_router = $router;
$path = '';
/**
* 检测URL模式以及是否开启自定义路由配置
*/
if($this->_router->getUrl() != '0' && $this->_router->getRouterOn()){
if(array_key_exists($this->_router->getPath(),$this->_router->getRule())){
$rule = $this->_router->getRule();
$path = $rule[$path];
}
}
/**
* URL参数匹配
*/
$this->parserParam($path);
}
public function parserParam($path)
{
$url = preg_replace('/\.html$/','',$path);
switch($this->_router->getUrlModel()){
case 0:
$this->initDispatchParamByNormal();
break;
case 1:
$dispatch = explode('/',trim($url,'/'));
if(in_array('index.php',$dispatch)){
$param['platform'] = isset($dispatch['1']) ? $dispatch['1'] : '';
$param['controller'] = isset($dispatch['2']) ? $dispatch['2'] : '';
$param['action'] = isset($dispatch['3']) ? $dispatch['3'] : '';
$this->getValue($url,4);
} else {
$param['platform'] = isset($dispatch['0']) ? $dispatch['0'] : '';
$param['controller'] = isset($dispatch['1']) ? $dispatch['1'] : '';
$param['action'] = isset($dispatch['2']) ? $dispatch['2'] : '';
$this->getValue($url,3);
}
$this->_router->setUrl($param);
$this->initDispatchParamByPathInfo();
break;
case 2:
$this->initDispatchParamByNormal();
break;
}
}
private function getValue($url,$start)
{
$get = explode('/',trim($url,'/'));
if(count($get)>3){
$param = array_slice($get,$start);
for($i=0;$i<count($param);$i+=2){
$_GET[$param[$i]] = $param[$i+1];
}
return $_GET;
}
}
/**
* 默认模式下初拼接分发参数
*/
private function initDispatchParamByNormal(){
//定义常量保存操作平台
define('PLATFORM',isset($_GET[$config['var_platform']]) ? strtolower($_GET[$config['var_platform']]) : static::$_default_platform);
//定义常量保存控制器
define('CONTROLLER',isset($_GET[$config['var_controller']]) ? ucfirst($_GET[$config['var_controller']]) : static::$_default_controller);
//定义常量保存操作方法
define('ACTION',isset($_GET[$config['var_action']]) ? strtolower($_GET[$config['var_action']]) : static::$_default_action);
}
/**
* pathinfo 模式下拼接分发参数
*/
private function initDispatchParamByPathInfo(){
//定义常量保存操作平台
$this->_router->setPlatform(
$this->_router->getUrl('platform') == ''
?
$this->_router->getDefaultPlatform()
:
strtolower($this->_router->getUrl('platform'))
);
//定义常量保存控制器
$this->_router->setController(
$this->_router->getUrl('controller') == ''
?
$this->_router->getDefaultController()
:
strtolower($this->_router->getUrl('controller'))
);
//定义常量保存操作方法
$this->_router->setAction(
$this->_router->getUrl('action') == ''
?
$this->_router->getDefaultAction()
:
strtolower($this->_router->getUrl('action'))
);
}
}
路由解析类,解析路由根据自定的规则找出该次请求的模块,控制器以及方法然后分发都各自的模块控制器方法中,如果没有即使用默认的模块控制器以及方法进行填补,我设置的默认模块是main。控制器是Home以及方法为main,如果解析后的URL没有相关配置会通过默认的配置进行分发。
将URL中分析出来的get参数进行设置到$_GET参数中获取自定义到其他类中,后续我将全部设置到请求类中,方便后期过滤。
class Dispatch
{
//分发方法
static public function dispatch(Router $router)
{
$dir = $router->getDir() . 'controller/' . $router->getPlatform();
//判断模块是否存在
if(!is_dir($dir)){
//抛出异常
throw new \Exception("无法加载模块");
}
//实例化控制器类
$controller_name = $router->getNamespace() . '\controller\\' . $router->getPlatform() . '\\' . $router->getController();
$filename = str_replace('\\','/',$dir . '/' . $router->getController() . '.php');
if(file_exists($filename)){
Application::bind(Application::definition()
->setAlias($controller_name)
->setIsSingleton(true)
->setClassName($controller_name));
} else {
//抛出异常
throw new \Exception("无法加载控制器");
}
//调用方法
$action_name = $router->getAction();
$controller = Application::get($controller_name);
if(method_exists($controller,$action_name)){
Application::run()->setData($controller->$action_name());
} else {
//抛出异常
throw new \Exception("无法加载方法");
}
}
}
分发类,将解析器中分析出来的模块控制器以及 方法设置到router类中,将router类注入到分发类中即可获取到请求的模块控制器方法,昨天说过要使用依赖注入根据浏览器请求自动注入到控制器中,这里便用到了依赖注入,补全控制器类名然后通过bind方法将控制器注入进行,然后通过get方法获取该控制器,经过依赖注入内部会进行分析实例的控制器内是否需要注入其他类,返回该控制器的实例,然后根据请求的方法进行调用控制器内的方法,这里将方法返回的信息都设置到request类中,有request中进行返回,所以这里建议的是,尽量不要在方法中使用echo进行输入还是使用标准的return返回数据,有request进行输出,如果由request接管输入输出对api开发更为友好,输出的格式可以通过配置进行改变,目前支持原始数据输出,json以及xml格式数据输出。
以上是关于php开源一个mvc框架的诞生之路由实现的主要内容,如果未能解决你的问题,请参考以下文章