SP的单入口模块化开发改造

#1 SunPSP

SP是一个很好框架,速度快,好上手,够小,J大又屌,自从用了SP之后就彻底抛弃了TP、CP
现在开发基本都是拿着SP打底子,没再到处找框架用了

用SP一年多,一直没处理好的问题就是模块化了
虽然手册提供了大规模部署的建议,但是那是多入口的,个人感觉用起来很累
正好最近公司一个平台要重构,给的时间比较充裕,就乘机处理了下SP的模块化问题

因为个人偏好问题,模块化之后SP的目录结构如下
ROOT(站点根目录)
    SpeedPHP(SP框架目录)
    Model(模型目录)
    Module(模块目录)
        Default(具体的独立模块目录,Default作为默认目录使用)
            Cache(缓存目录,临时文件都放这边)
            Controller(模块控制器目录)
            Template(模块模板目录)
            spConfig.php(模块配置文件)
    index.php(根目录下的单入口文件)

个人理解,模块化模块化
模块间就得独立,相互间几乎不存在耦合问题
任何模块的拆装都不应该影响其他模块的影响
而且,模块拆装必须得简单干净,没有残留
模块相关的缓存、模板、控制器等独有的东西,也得一步到位
手册中大规模部署存在的一个问题就是添加移除都很麻烦
装个新应用,就得在根目录加一个入口文件,然后控制器目录加一个控制器,再去模板目录建一个同名的模板目录
这样设置的好处是,新加一个应用,直接把应用目录复制进来就完事儿了,卸载模块也只需要删除这个模块目录,就什么都不剩下了
简单明了干干净净

目录设置好了,下面就是程序的改造了,让SP能按着这个目录来组织程序运行
首先是入口文件
@header('Content-type:text/html;charset=UTF-8');
define('DS',DIRECTORY_SEPARATOR);
define('ROOT_PATH',str_replace(DS,'/',dirname(__FILE__)));
define('SP_PATH',str_replace(DS,'/',dirname(__FILE__)).'/SpeedPHP');
define('MODULE','m');
//载入框架启动器
require(SP_PATH.'/SpeedPHP.php');
spRun();
跟SP默认的入口文件对比,就是少了$spConfig变量,加了一个MODULE常量
这个配置我移到了模块的配置文件中

接下来模块的配置文件,在模块配置文件中定义该模块所在目录,以及该模块的配置信息
其实就是将默认的入口文件一拆为二,全局的放在入口问价哪种,模块相关部分的参数移到模块配置文件中
define('APP_PATH',str_replace(DS,'/',dirname(__FILE__)));
$spConfig = array(
        'controller_path' => APP_PATH.'/Controller',//控制器目录
        'view' => array(//视图配置
                'config' => array(
                        'template_dir' => APP_PATH.'/Template',//模板目录
                        'compile_dir' => APP_PATH.'/Cache/ViewCompile',//编译目录
                        'cache_dir' => APP_PATH.'/Cache/ViewCache',//缓存目录
                ),
        ),
);
再接着是怎么让SP从入口文件根据将要访问的模块读取对应模块目录下的配置文件
这里有两种方式,一种是根据域名判断,还一种是根据URL带的参数来判断
其实原理都一样,就是做个记录,哪个参数对应那个模块
考虑到单域名多模块使用场景比较多,就选择了URL参数判断这种方式
也就是/index.php?m=Default&c=home&a=index这种形式
用URL中的m参数来带模块值
然后就简单了,都不需要自己写函数来获取m参数
SP本来就有个神器spArgs
果断复制一边改名字为spModule,往spConfig.php里面一扔
然后new一下,require一下搞定
$spModuleConfig = new spModule;
require(ROOT_PATH.'/Module/'.$spModuleConfig->get(MODULE,'Default').'/'.'spConfig.php');
为什么不import,为什么不spClass?呵呵~

继续,现在需要改造下spUrl,让他生成URL的时候能加进去模块参数
function spUrl($module = null,$controller = null,$action = null,$args = null,$anchor = null,$no_sphtml = FALSE){
        if(TRUE == $GLOBALS['G_SP']['html']["enabled"] && TRUE != $no_sphtml){
                //当开启HTML生成时,将查找HTML列表获取静态文件名称。
                $realhtml = spHtml::getUrl($controller,$action,$args,$anchor);
                if(isset($realhtml[0]))return $realhtml[0];
        }
        $module = (null != $module) ? $module : $GLOBALS['G_SP']["default_module"];
        $controller = (null != $controller) ? $controller : $GLOBALS['G_SP']["default_controller"];
        $action = (null != $action) ? $action : $GLOBALS['G_SP']["default_action"];
        //使用扩展点
        if($launch = spLaunch("function_url",array('module'=>$module,'controller'=>$controller,'action'=>$action,'args'=>$args,'anchor'=>$anchor,'no_sphtml'=>$no_sphtml),TRUE ))return $launch;
        if(TRUE == $GLOBALS['G_SP']['url']["url_path_info"]){//使用path_info方式
                $url = $GLOBALS['G_SP']['url']["url_path_base"]."/{$module}/{$controller}/{$action}";
                if(null != $args){
                        foreach($args as $key => $arg){
                                $url .= "/{$key}/{$arg}";
                        }
                }
        }else{
                $url = $GLOBALS['G_SP']['url']["url_path_base"]."?".MODULE."={$module}&".$GLOBALS['G_SP']["url_controller"]."={$controller}&";
                $url .= $GLOBALS['G_SP']["url_action"]."={$action}";
                if(null != $args){
                        foreach($args as $key => $arg){
                                $url .= "&{$key}={$arg}";
                        }
                }
        }
        if(null != $anchor) $url .= "".$anchor;
        return $url;
}
红色这几行,对比下就知道只是简单地在原函数基础上插进去几个参数而已,完事儿

最后,得试试这么改行不行的通么
默认模块下建个控制器,然后输出几个配置关键配置瞅瞅
class main extends spController{
        public function index(){
                echo '根目录:'.ROOT_PATH.'
';
                echo '模块目录:'.APP_PATH.'
';
                echo '框架目录:'.SP_PATH.'
';
                echo '模板目录:'.$GLOBALS['G_SP']['view']['config']['template_dir'].'
';
                echo '控制器目录:'.$GLOBALS['G_SP']['controller_path'].'
';
                echo 'URL:'.spUrl().'
';
        }
}
输出如下
根目录:D:/WebServer/apache-2.4.10-win32-VC11/htdocs/Default
模块目录:D:/WebServer/apache-2.4.10-win32-VC11/htdocs/Default/Module/Default
框架目录:D:/WebServer/apache-2.4.10-win32-VC11/htdocs/Default/spCore
模板目录:D:/WebServer/apache-2.4.10-win32-VC11/htdocs/Default/Module/Default/Template
控制器目录:D:/WebServer/apache-2.4.10-win32-VC11/htdocs/Default/Module/Default/Controller
URL:/default/index.php?m=Default&c=home&a=index
SP我没有放在根目录下
D:/WebServer/apache-2.4.10-win32-VC11/htdocs/Default
这个是这次测试的根目录,检查一遍,木有出错,收工

到这里SP的模块化改造就完成了
目前没有经过严格测试,只是目测上可行,理论上也可行
具体还得等做几个DEMO来测试才行
不知道J大以及各位大神有木有空出来指导下如何给SP加上模块化特性

PS:
这么改完之后,一直有个疙瘩梗着难受
本人是规则控,爬代码啥子的追求统一一致
这里就有个破坏队形的
入口文件有一句
define('MODULE','m');
这个用来定义URL中模块参数标识
跟配置文件中的
'url_controller' => 'c',//请求时使用的控制器变量标识
'url_action' => 'a',//请求时使用的动作变量标识
是一个性质的东西
那么按着规则控的一致性原则,怎么着也得
'url_module' => 'm
写到配置中去啊
可是在spConfigReady到$GLOBALS['G_SP']之前,配置文件不起作用。。。。
谁有好法子解决不?

2014-11-07 16:41:40

#2 jake

可以看看 https://code.google.com/p/speedphp/source/list

这个,应该是已经有实现module,主要是写法的兼容方面问题而已

2014-11-07 17:23:26

#3 skyzong

前几天公司程序要用TP开发,我学了一下,感觉太复杂,不如SP好用

2015-02-03 18:03:28

#4 lvqing

呵呵,现在 google 被墙得太厉害,有一些的非常好的文章或者扩展库在 code.google 上。能在墙内做下镜像不?也许这个要求有点过分了。

2015-02-28 11:21:55

#5 jake

lvqing 发表于 2015-2-28 11:21
呵呵,现在 google 被墙得太厉害,有一些的非常好的文章或者扩展库在 code.google 上。能在墙内做下镜像不 ...
fan ^ qiang 是开发人员必备的技能,你懂的{:soso_e144:}

2015-02-28 13:33:40

#6 lvqing

好吧,只是 墙 越来越厉害了,呵呵

2015-02-28 16:31:09