MVC的调度器和模板类
程序员文章站
2022-04-03 10:39:01
...
调整了设置参数的的方法
新增了普通路由模式
pathinfo模式支持伪静态了
pathinfo现在支持用户自定义路由了
新增了普通路由模式
pathinfo模式支持伪静态了
pathinfo现在支持用户自定义路由了
<?php /** * {loop $array $key $value}..........{/loop} 循环 * {loop $array $value}..........{/loop} 循环 * {if condition}...{elseif condition}..{else}..{/if} if条件语句 * {$val} 输出变量值 * {eval echo"ok";} 运行PHP代码 * {template file} 包含另外一个模版 */ class Template { private static $tDir; //模版文件目录 private static $tTmpDir; //编译好后的文件目录 private $tVal; //模版变量 private $tFile; //模版文件 private $tContent; //模版内容 private static $uDispatcher; //URL调度器 private static $real = false; //实时编译 public function __construct() { $this->tVal = array(); } /** * 设置模版文件目录 * @param string $dir */ public static function setTemplateDir($dir) { self::$tDir = $dir; } /** * 是否实时编译 * @param bool $real */ public static function setReal($real) { self::$real = (bool) $real; } /** * 临时文件目录 * @param string $dir */ public static function setTmpDir($dir) { if (!file_exists($dir)) { if (!mkdir($dir, 0, true)) die("tmp dir $dir can't to mkdir"); } self::$tTmpDir = realpath($dir); } /** * URL调度器 * @param Dispatcher $dispatcher */ public static function setU(&$dispatcher) { if (is_object($dispatcher) && method_exists($dispatcher, 'U')) { self::$uDispatcher = $dispatcher; } } /** * 变量赋值 * @param mixed $name * @param mixed $value */ public function assign($name, $value) { $this->tVal[$name] = $value; } /** * 取得模版的变量 * @param string $name */ public function getVal($name) { if (isset($this->tVal[$name])) { return $this->tVal[$name]; }else return false; } /** * 将运行好后的内容,保存到一个html文件中 * @param string $tFile * @param string $html */ public function saveHtml($tFile, $html) { ob_start(); $this->display($tFile); $buffer = ob_get_contents(); ob_end_clean(); file_put_contents($html, $buffer); } /** * 运行并显示模版内容 * @param string $tfile */ public function display($tFile) { $this->tFile = $this->parseTemplatePath($tFile); if (!self::$real) { if (!file_exists($this->getTmpFile())) $this->parse(); elseif ((filemtime($this->tFile) > filemtime($this->getTmpFile()))) $this->parse(); }else $this->parse(); extract($this->tVal, EXTR_OVERWRITE); include $this->getTmpFile(); } /** * 编译好后的文件 * @return string $filepath */ private function getTmpFile() { $basename = basename($this->tFile); $pos = strrpos($basename, '.'); $tmp = 'tpl_' . substr($basename, 0, $pos) . '.php'; return self::$tTmpDir . '/' . $tmp; } private function parse() { $this->tContent = file_get_contents($this->tFile); $this->parseInclude(); $this->parseSection(); $this->parseVal(); $this->parseEval(); file_put_contents($this->getTmpFile(), $this->tContent); } private function parseInclude() { $this->tContent = preg_replace("/{templates+([a-zA-z0-9._]+)}/ies","$this->subtemplate('$1')", $this->tContent); } /** * 获取只模版 * @param string $file */ private function subtemplate($file) { return file_get_contents($this->parseTemplatePath($file)); } /** * 解析模版路径 * @param string $file * @return string $filepath */ private function parseTemplatePath($tFile) { $tFile.='.html'; $tFile = self::$tDir ? self::$tDir . '/' . $tFile : $tFile; if (!file_exists($tFile)) { die("No template file $tFile"); } else { $tFile = realpath($tFile); } return $tFile; } /** * 解析变量 */ private function parseVal() { $this->tContent = preg_replace("/{(\$S+?)}/is","<?php echo \1 ;?>", $this->tContent); } /** * 解析段落 */ private function parseSection() { //逻辑 $this->tContent = preg_replace("/{elseifs+(.+?)}/ies","$this->stripvtags('<?php } elseif(\1) { ?>','')", $this->tContent); $this->tContent = preg_replace("/{else}/is","<?php } else { ?>", $this->tContent); $this->tContent = preg_replace("/{U((.+?))}/ies","$this->parseUrl('$1')", $this->tContent); //循环 for ($i = 0; $i < 6; $i++) { $this->tContent = preg_replace("/{loops+(S+)s+(S+)}(.+?){/loop}/ies","$this->stripvtags('<?php if(is_array(\1)) { foreach(\1 as \2) { ?>','\3<?php } } ?>')", $this->tContent); $this->tContent = preg_replace("/{loops+(S+)s+(S+)s+(S+)}(.+?){/loop}/ies","$this->stripvtags('<?php if(is_array(\1)) { foreach(\1 as \2 => \3) { ?>','\4<?php } } ?>')", $this->tContent); $this->tContent = preg_replace("/{ifs+(.+?)}(.+?){/if}/ies","$this->stripvtags('<?php if(\1) { ?>','\2<?php } ?>')", $this->tContent); } } private function stripvtags($expr, $statement='') { $expr = str_replace("\"",""", preg_replace("/<?=(\$.+?)?>/s","\1", $expr)); $statement = str_replace("\"",""", $statement); return $expr . $statement; } /** * 解析PHP语句 */ private function parseEval() { $this->tContent = preg_replace("/{evals+(.+?)}/is","<?php $1 ?>", $this->tContent); } /** * 解析URL */ private function parseUrl($url) { if (is_object(self::$uDispatcher)) { return self::$uDispatcher->U($url); } else { return $url; } } } ?>
<?php /** * 控制调度器 * 先定义APP_PATH常量 制定应用程序目录 * 默认模块目录 APP_PATH 目录下面的 Action目录 * 默认控制器为IndexAction * 默认模块名为index * 默认参数分隔符为"/",可选"-" * 默认入口文件为index.php * 模块的类名必须和文件同名,比如:IndexModule则它的文件名为IndexModule.class.php * 可通过setOption方法设置一些参数 * pathinfo模式支持伪静态 * 新增普通url模式 * setOption参数说明 * 传进去的是数组键值对形式的参数 * 设置选项条件,可设置的有 * MODULE_PATH=>查找模块目录的位置 * DEFAULT_MODULE=>默认Module * DEFAULT_ACTION=>默认Action * DEBUG=>开启调试(true|false) * URL_MODEL=>路由模式(0:普通模式,1:pathinfo模式) * URL_DELIMITER=>参数分隔符 pathinfo模式使用 * URL_HTML_SUFFIX=>'文件后缀' pathinfo模式伪静态使用 * ENTRY_INDEX=>入口文件 * URL_ROUTER_ON=>开启自定义路由 * 普通URL模式U(模块名/操作名?参1=值1&参2=值2) * 路由模式U(路由名@?参1=值1&参2=值2) */ class Dispatcher { private static $instance; private static $_SGLOBAL; //调度配置 private static $route = array(); //泛路由 private function __construct() { self::initConfig(); } public static function getInstance() { if (!self::$instance instanceof self) { self::$instance = new self(); } return self::$instance; } private function __clone() { } /** * 运行控制器 */ public function run() { $route = array(); if (self::$_SGLOBAL['URL_MODEL'] == 1) { $route = $this->pathInfoRoute(); } else { $route = $this->generalRoute(); } $modulefile = self::$_SGLOBAL['MODULE_PATH'] ."/{$route['module']}.class.php"; if (file_exists($modulefile)) { include $modulefile; if (class_exists($route['module'])) { $class = new $route['module']; if (method_exists($class, $route['action'])) { call_user_func(array(&$class, $route['action'])); }else die("in <b>{$route['module']}</b> module no this <b>{$route['action']}</b> action"); }else die("no this <b>{$route['module']}</b> module"); }else { die("no this <b>{$route['module']}</b> module"); } self::$_SGLOBAL['endtime'] = microtime(true); $this->debugInfo(); } /** * 输出调试信息 */ private function debugInfo() { if (self::$_SGLOBAL['DEBUG']) { $exectime = self::$_SGLOBAL['endtime'] - self::$_SGLOBAL['starttime']; $debuginfo = <<<HTML <style type="text/css"> .dispatcher_debug_table th,.dispatcher_debug_table td{padding:5px;} .dispatcher_debug_table th{ border-top:1px solid red; border-left:1px solid red; background-color:#ccc; } .dispatcher_debug_table td{ border-top:1px solid red; border-left:1px solid red; border-right:1px solid red; } .dispatcher_debug_table_last td,.dispatcher_debug_table_last th{ border-bottom:1px solid red; } .dispatcher_debug_table_title{border-right:1px solid red;} </style> <table class="dispatcher_debug_table"cellpadding="0"cellspacing="0"> <tr><th class="dispatcher_debug_table_title">Debug Info</th></tr> <tr> <th>Execute Time</th><td>$exectime s</td> </tr> <tr><th>Include File</th><td> HTML; foreach (get_included_files () as $file) { $debuginfo.=$file ."<br/>"; } $debuginfo.="<tr><th>Server Info</th><td>"; $debuginfo.="Host:". $_SERVER['HTTP_HOST'] ."<br/>"; $debuginfo.="PHP_Version:". PHP_VERSION ."<br/>"; $debuginfo.="Server_Version:". $_SERVER['SERVER_SOFTWARE'] ."<br/>"; $debuginfo.="</td></tr>"; $debuginfo.="<tr class='dispatcher_debug_table_last'><th>Client Info</th><td>"; $debuginfo.="Remote_Addr:". $_SERVER['REMOTE_ADDR'] ."<br/>"; $debuginfo.="User_Agent:". $_SERVER['HTTP_USER_AGENT'] ."<br/>"; $debuginfo.="</td></tr>"; $debuginfo.="</table>"; echo $debuginfo; } } private function generalRoute() { $route = array(); $route['module'] = !empty($_GET['m']) ? $_GET['m'] : self::$_SGLOBAL['DEFAULT_MODULE']; $route['action'] = !empty($_GET['a']) ? $_GET['a'] : self::$_SGLOBAL['DEFAULT_ACTION']; $route['module'].='Action'; unset($_GET['m']); unset($_GET['a']); return $route; } /** * PATHINFO形式的路由调度 * 支持伪静态 */ private function pathInfoRoute() { $route = array(); //伪静态 if (self::$_SGLOBAL['URL_HTML_SUFFIX']) { $pos = strlen($_SERVER['PATH_INFO']) - strlen(self::$_SGLOBAL['URL_HTML_SUFFIX']); $_SERVER['PATH_INFO'] = substr($_SERVER['PATH_INFO'], 0, $pos); } if (!$_SERVER['PATH_INFO'] || $_SERVER['PATH_INFO'] == '/') { $route = array('module' => self::$_SGLOBAL['DEFAULT_MODULE'], 'action' => self::$_SGLOBAL['DEFAULT_ACTION']); } else { $_SERVER['PATH_INFO'] = substr($_SERVER['PATH_INFO'], 1); $pathinfo = explode(self::$_SGLOBAL['URL_DELIMITER'], $_SERVER['PATH_INFO']); //用户自定义路由 if (self::$_SGLOBAL['URL_ROUTER_ON'] && in_array($pathinfo[0], array_keys(self::$route))) { $route['module'] = self::$route[$pathinfo[0]][0]; $route['action'] = self::$route[$pathinfo[0]][1]; $c = explode(',', self::$route[$pathinfo[0]][2]); array_shift($pathinfo); foreach ($c as $r) { $_GET[$r] = array_shift($pathinfo); } } else { if (count($pathinfo) < 2) { $route['module'] = $pathinfo[0] . self::$_SGLOBAL['MODULE_SUFFIX']; $route['action'] = self::$_SGLOBAL['DEFAULT_ACTION'] . self::$_SGLOBAL['ACTION_SUFFIX']; } else { $route['module'] = array_shift($pathinfo) . self::$_SGLOBAL['MODULE_SUFFIX']; $route['action'] = array_shift($pathinfo) . self::$_SGLOBAL['ACTION_SUFFIX']; } } if (count($pathinfo) >= 2) { for ($i = 0, $cnt = count($pathinfo); $i < $cnt; $i++) { if (isset($pathinfo[$i + 1])) { $_GET[$pathinfo[$i]] = $pathinfo[++$i]; } } } } $route['module'].='Action'; $_REQUEST = array_merge($_GET, $_POST); return $route; } /** * url地址组合 * 格式为:Module/Action?get=par(模块名/动作名?get参数) * @param string $url * @return string $url */ public static function U($url) { $pathinfo = parse_url($url); $path = ''; $get = array(); $inroute = false; //用户定义的路由 if (isset($pathinfo['query'])) { $query = explode('&', $pathinfo['query']); foreach ($query as $q) { list($k, $v) = explode('=', $q); $get[$k] = $v; } } if (!self::$_SGLOBAL) { self::initConfig(); } //pathinfo方式的url if (self::$_SGLOBAL['URL_MODEL'] == 1) { if (self::$_SGLOBAL['URL_ROUTER_ON'] && strpos($pathinfo['path'], '@') !== false) { //取出所有用户定义的路由 $routeNames = array_keys(self::$route); $p = substr($pathinfo['path'], 0, -1); if (in_array($p, $routeNames)) { $inroute = true; $path.='/' . $p; $c = explode(',', self::$route[$p][2]); foreach ($c as $v) { if (isset($get[$v])) { $path.=self::$_SGLOBAL['URL_DELIMITER'] . $get[$v]; unset($get[$v]); } } } } if (!$inroute) { if (isset($pathinfo['path'])) { list($module, $action) = explode('/', $pathinfo['path']); $module = $module ? $module : self::$_SGLOBAL['DEFAULT_MODULE']; $action = $action ? $action : self::$_SGLOBAL['DEFAULT_ACTION']; } else { $module = self::$_SGLOBAL['DEFAULT_MODULE']; $action = self::$_SGLOBAL['DEFAULT_ACTION']; } $path ="/$module". self::$_SGLOBAL['URL_DELIMITER'] . $action; } if (!empty($get)) { foreach ($get as $k => $v) { $path.=self::$_SGLOBAL['URL_DELIMITER'] . $k . self::$_SGLOBAL['URL_DELIMITER'] . $v; } } //url伪静态 if (self::$_SGLOBAL['URL_HTML_SUFFIX']) { $path.=self::$_SGLOBAL['URL_HTML_SUFFIX']; } } elseif (self::$_SGLOBAL['URL_MODEL'] == 0) { $url = parse_url($url); if (isset($url['path'])) { list($module, $action) = explode('/', $url['path']); $module = $module ? $module : self::$_SGLOBAL['DEFAULT_MODULE']; $action = $action ? $action : self::$_SGLOBAL['DEFAULT_ACTION']; } else { $module = self::$_SGLOBAL['DEFAULT_MODULE']; $action = self::$_SGLOBAL['DEFAULT_ACTION']; } $path.="?m=$module&a=$action"; if ($url['query']) { $path.='&' . $url['query']; } } if (!self::$_SGLOBAL['URL_REWRITE']) $path = '/' . self::$_SGLOBAL['ENTRY_INDEX'] . $path; return $path; } /** * 初始化配置信息 */ private static function initConfig() { if (defined('APP_PATH')) { //默认模块目录 self::$_SGLOBAL['MODULE_PATH'] = APP_PATH . '/action'; } self::$_SGLOBAL['DEFAULT_ACTION'] = 'index'; //默认action self::$_SGLOBAL['DEFAULT_MODULE'] = 'Index'; //默认module //默认url路由模式,1:pathinfo模式,0为普通模式 self::$_SGLOBAL['URL_MODEL'] = 1; self::$_SGLOBAL['URL_DELIMITER'] = '/'; //参数分隔符 self::$_SGLOBAL['ENTRY_INDEX'] = 'index.php'; self::$_SGLOBAL['URL_HTML_SUFFIX'] = null; //url伪静态 self::$_SGLOBAL['URL_REWRITE'] = false; //URL重写 self::$_SGLOBAL['starttime'] = microtime(true); self::$_SGLOBAL['URL_ROUTER_ON'] = false; //是否启用路由功能 self::$_SGLOBAL['DEBUG'] = false; } /** * 设置选项条件,可设置的有 * MODULE_PATH=>查找模块目录的位置 * DEFAULT_MODULE=>默认Module * DEFAULT_ACTION=>默认Action * DEBUG=>开启调试(true|false) * URL_DELIMITER=>参数分隔符 * URL_MODEL=>路由模式(0:普通模式,1:pathinfo模式) * URL_HTML_SUFFIX=>'文件后缀' pathinfo模式伪静态使用 * ENTRY_INDEX=>入口文件 * URL_ROUTER_ON=>开启自定义路由 * @param array $option 选项 */ public function setOption($option) { $o = array('MODULE_PATH', 'DEFAULT_MODULE', 'DEFAULT_ACTION', 'DEBUG', 'URL_DELIMITER', 'URL_MODEL', 'URL_HTML_SUFFIX', 'ENTRY_INDEX', 'URL_REWRITE', 'URL_ROUTER_ON'); foreach ($option as $k => $v) { if (in_array($k, $o)) { self::$_SGLOBAL[$k] = $v; } } } /** * 设置路由 * array('route'=>array('模块名称', '操作名称','参数1,参数2,参数3')) * @param array $route 路由 */ public function setRoute($route) { self::$route = $route; } } ?>
<?php include 'action/CommonAction.class.php'; require 'mvc/Dispatcher.class.php'; require 'mvc/Template.class.php'; $dispatcher = Dispatcher::getInstance(); //控制器选项 $option = array('DEBUG' => 1, 'URL_MODEL' => 1, 'URL_DELIMITER' => '/', 'DEFAULT_ACTION' => 'home', 'URL_REWRITE' => 1, 'URL_ROUTER_ON' => true, 'URL_HTML_SUFFIX'=>'.html'); //自定义泛路由 $router = array('space'=>array('Space', 'index','uid')); $dispatcher->setOption($option); $dispatcher->setRoute($router); Template::setU($dispatcher); Template::setReal(true); Template::setTemplateDir('template/default'); Template::setTmpDir('runtime/tpl'); $dispatcher->run(); ?>
推荐阅读
-
ASP.NET MVC 主要的四种过滤器和三种具体实现类
-
MVC使用T4模板生成其他类的具体实现学习笔记2
-
PHP获取浏览器信息类和客户端地理位置的2个方法
-
Bottle框架中的装饰器类和描述符应用详解
-
ASP.NET MVC 主要的四种过滤器和三种具体实现类
-
MVC使用T4模板生成其他类的具体实现学习笔记2
-
C#_Excel数据读取与写入_自定义解析封装类_支持设置标题行位置&使用excel表达式收集数据&单元格映射&标题映射&模板文件的参数数据替换(第二版-增加深度读取和更新功能)
-
第一次作业:关于Linux 2.6.20进程模型和O(1)调度器算法的分析
-
PHP获取浏览器信息类和客户端地理位置的2个方法
-
前端开发HTML&css入门——伪类选择器和一些特殊的选择器