• 技术文章 >php教程 >PHP源码

    MVC的调度器和模板类

    PHP中文网PHP中文网2016-05-25 17:15:09原创589
    调整了设置参数的的方法

    新增了普通路由模式

    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();
    ?>
    声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn核实处理。
    上一篇:很简单的一个socket客户端类 下一篇:采集 PHP

    相关文章推荐

    • PHP禁止图片文件的被盗链函数• 使用simple_html_dom抓取oschina的新闻资讯• 解决json_encode 函数中文被编码成 null的办法• php学习笔记之面向对象编程• php中常用的函数集合

    全部评论我要评论

  • 取消发布评论发送
  • 1/1

    PHP中文网