PHP China | 中国开源之路 's Archiver

wbsifan 发表于 2008-11-14 11:01

关于单入口模式思考

先跟大家问个好, 来PHPCHINA有一段时间了,一直潜水.
今天冒个泡,说一下我对单入口模式的一些想法.

这个问题源自,我的MYPIC项目(一个图片管理系统)
写个项目的时候采用了单入口的模式, 根据GET参数 动态加载ACTION和方法.
根目录下面只有 index.php 是前台的入口,admin.php 是后台的入口

[php]
//网站根目录 ROOT_PATH
define('ROOT_PATH', str_replace("\\", "/", dirname(__FILE__)).'/');
//加载核心
require(ROOT_PATH.'core/start.php');
//加载主控制器
$app = new app();
//开始执行
$app->run();
[/php]

start.php 负责系统常量的定义,核心函数加载和一些初始化的操作.
要调用哪个控制器, 调用控制器里的哪个方法? 这些都是在 app 类 run()方法里实现的.
注:只贴出了代码片段:

[php]
class app {

// 设置控制器目录
public function control($action='action'){
  // 可以把控制器文件分放到不同的文件夹里,然后在这里指定
}

// run
public function run($l1=null, $l2=null){
  try {
   $this->init();  // 初始化
   $this->exec($l1, $l2);   // 开始加载控制器并运行方法
  } catch (Error $err){
   error($err);   // 捕获异常
  }
}

// 初始化
public function init(){
  // 项目编译
  $this->bulid();
  // 设置错误级别
  // 设置系统时区 PHP5支持
     // 清除危险变量
  // 解析魔术引号
  // 禁止对全局变量注入
  // 定义一些要用到的常量
}


// 项目编译
public function bulid(){
  // 加载核心配置
  // 加载用户配置
  // 加载RULE规则
       // 加载语言包
  // 加载兼容函数库
}
  
// 运行控制器
public function exec($l1=null, $l2=null){
  // 分析 URL 模式
  $this->parseUrl();
  // 获取 M AND A
  // 加载控制器
  // 实例化控制器
  $app = new $l1;
  // 运行指定的方法
  $app->$l2();
}

// 分析 URL 模式
public function parseUrl(){
  // 分析GET参数,包括控制器名和方法以及其它的GET参数
  // 分析路由规则
}
}
[/php]
一个单入口的模式就建立好了, 只要定义好 controller 类,和不不同的方法,例如可以定义:
[php]
// 定义User控制器
class User extends Action {
// 处理与注册相关的流程
public function reg(){
  // doing....
}
}
[/php]

然后通过类似于  index.php?m=user&a=reg 的型式及可以调用

这样做好处:

1.所有的操作都是在run()内完成, 并且是在一个try..catch内执行,
所以不管是前台和后台都可以方便的捕获到异常.

2.不用担心用户访问到不该访问的页面.
只把可以供用户访问的方法定义为 public, 其它的定义为私有方法protected,

3.可以统一处理系统相关的常量和一些初始化操作.

4.因为所有操作都是相对于根目录,使得include 更加的方便,

5.可以在parseUrl()里处理伪静态,方便的实现PATH_INFO 等各种型式的伪静态.

以上说的是优点, 但是我在使用的过程中,也碰到了许多问题. 比如一个最直观的,
URL 太长了!  一个列表页完整的URL:
[url=http://wobuzhidao.com/index.php?m=list&a=show&sid=20]http://wobuzhidao.com/index.php?m=list&a=show&sid=20[/url]
而一个普通模式的URL可能是这样:
[url=http://wozhidaole.com/list.php?sid=20]http://wozhidaole.com/list.php?sid=20[/url]

用户会更喜欢哪一个呢? 我猜一定是后者吧.如何处理这个问题呢?
我们可以定义一个路由的规则,即把一定义一些 值 对应于 某组固定的 控制器和方法:
[php]
array('list' => array('list','show',array('sid','p')));
[/php]
上面的规则表示,只要从URL获取到的路由名是list,
根据上述对应规则,分析到 是加载 list show.
就自动 执行 $list->show(),
并且GET参数按顺序为 $_GET['sid'] 和 $_GET['p'] 的值.还是举个例子吧:
用户访问如下地址
[url=http://zhidaole.com/index.php/list-1-2.html]http://zhidaole.com/index.php/list-1-2.html[/url]

我们的parseUrl()方法,会分析到有list,路由, 所以会自动调用list 控制器 和show 方法.
后面的两个参数则对应 $_GET['sid']=1,  $_GET['p']=2.
是不是短了很多?  这样子效果就和普通模式接近了,而且更加方便的实现了伪静态.

具体的parseUrl()方法就贴了,请自行实现.
先就说这么多了,如果你有兴趣可以百度一下 mypic  看看具体的代码.
大家可以说说对于单入口模式的一些想法.

[[i] 本帖最后由 wbsifan 于 2008-11-14 11:14 编辑 [/i]]

七月十五 发表于 2008-11-14 11:09

楼主这么设计自有道理
其实楼主的class app相当于一个框架的controller了
楼主可以单一从index.php进入
又提供了从模块直接入口的方式
至于list.php还是index.php?m=list 是否合理值得探讨


谢谢分享

thatday 发表于 2008-11-14 11:24

mypic框架不错,完全OO,扩展方便。

ZendFramework 发表于 2008-11-14 13:45

单入口模式确实很好,方便统一管理和维护..
一个很大的缺陷就是每次在执行商业逻辑代码前,都必须有大量的非商业逻辑代码用来协调整个系统.
controller的路由和分发都是需要消耗资源的..
假如每天1000万次请求,那么就要1000次的路由和转发过程..这个消耗也是非常惊人的..
而非单入口的模式可以直接让脚本最快的进入商业逻辑.
有得必有失.

shebao 发表于 2008-11-14 13:48

讲解的不错.不过有点广告嫌疑.:lol:

又多了个框架...现在泛滥了

fhjr999 发表于 2008-11-14 14:19

[quote]原帖由 [i]shebao[/i] 于 2008-11-14 13:48 发表 [url=http://bbs.phpchina.com/redirect.php?goto=findpost&pid=719662&ptid=90756][img]http://bbs.phpchina.com/images/common/back.gif[/img][/url]
讲解的不错.不过有点广告嫌疑.:lol:

又多了个框架...现在泛滥了 [/quote]

不是所有的单一入口都是框架的,也可以仅仅用单一入口,单一入口相对来说,确实有很多方便之处。

simpleboy 发表于 2008-11-14 15:09

看了下~~ 思路和thinkphp好像? 借用? 调用配置都一样

fhjr999 发表于 2008-11-14 15:15

[quote]原帖由 [i]simpleboy[/i] 于 2008-11-14 15:09 发表 [url=http://bbs.phpchina.com/redirect.php?goto=findpost&pid=720121&ptid=90756][img]http://bbs.phpchina.com/images/common/back.gif[/img][/url]
看了下~~ 思路和thinkphp好像? 借用? 调用配置都一样 [/quote]

单一模式也就那么回事,思路,流程都是差不多的,只有具体实现细节不同罢了。

sentrychen 发表于 2008-11-14 17:04

[quote]原帖由 [i]ZendFramework[/i] 于 2008-11-14 13:45 发表 [url=http://bbs.phpchina.com/redirect.php?goto=findpost&pid=719647&ptid=90756][img]http://bbs.phpchina.com/images/common/back.gif[/img][/url]
单入口模式确实很好,方便统一管理和维护..
一个很大的缺陷就是每次在执行商业逻辑代码前,都必须有大量的非商业逻辑代码用来协调整个系统.
controller的路由和分发都是需要消耗资源的..
假如每天1000万次请求,那么 ... [/quote]
嗯,特别是在ajax处理的时候,让人很恼火

stylecn 发表于 2008-11-14 21:51

每天1000万次请求就不是一台机子在跑了。更不会用到单入口模式。

fhjr999 发表于 2008-11-14 22:09

仅仅一个单入口,并没有多少代码。跟其他的比起来就微不足道了。

FreeLiver 发表于 2008-11-14 22:32

顶,这种模式确实在不少框架中都有应用……学习了

FreeLiver 发表于 2008-11-14 22:39

这种模式原始版本是不是这样呀:
index.php 入口文件 根据$_GET['action;]加载不同的文件
[php]
switch($_GET["action"]){
case "reg":
include("reg.class.php");
break;
case "index":
include("index.class.php");
break;
[/php]

ljxok2001 发表于 2008-11-14 23:47

其实网址长一点,.普通用户根本不敏感, 你看淘宝,就故意把网址弄到火车那么长.

ZendFramework 发表于 2008-11-15 13:00

[quote]原帖由 [i]stylecn[/i] 于 2008-11-14 21:51 发表 [url=http://www.phpchina.com/bbs/redirect.php?goto=findpost&pid=721025&ptid=90756][img]http://www.phpchina.com/bbs/images/common/back.gif[/img][/url]
每天1000万次请求就不是一台机子在跑了。更不会用到单入口模式。 [/quote]
我只是随便列了个数据打个比方.
谁告诉你集群模式下不能用单入口模式?

七月十五 发表于 2008-11-15 13:07

[quote]原帖由 [i]ZendFramework[/i] 于 2008-11-15 13:00 发表 [url=http://bbs.phpchina.com/redirect.php?goto=findpost&pid=721812&ptid=90756][img]http://bbs.phpchina.com/images/common/back.gif[/img][/url]

我只是随便列了个数据打个比方.
谁告诉你集群模式下不能用单入口模式? [/quote]

有道理,不知道squid能否实现,愿闻高见

ZendFramework 发表于 2008-11-15 15:30

回复 17# 七月十五 的帖子

我觉得越来越跑题了,讨论的这些都和能不能用单入口模式没有关系.

quanhaier 发表于 2008-11-15 15:50

有得有失
?controler=default&action=ad&page=2&type=5
这样得url程序解析起来比较方便容易,虽然不友好
?/list-3-4-5.html
这样的url毕竟需要程序去解析,而且要遵循一定的规范,耗费资源
我觉得,在URL里只要有了‘?’号,这个符号,基本就是不友好的了,再去优化问号‘?’后面的url,显得有点多余,画蛇添足

[[i] 本帖最后由 quanhaier 于 2008-11-15 15:52 编辑 [/i]]

七月十五 发表于 2008-11-15 16:04

ZF的:index.php/module/controller/action/param1/value1/param2/value2
CI的:index.php/controller/action/param1_value/param2_value

可以通过.htaccess的rewrite规则去掉index.php

很友好,也很直观


BTW:CI对于url params的处理看上去要比ZF顺眼一些,利用了mothod参数

[[i] 本帖最后由 七月十五 于 2008-11-15 16:05 编辑 [/i]]

laopi 发表于 2008-11-16 11:27

讨论的很好~ 喜欢这样的帖子。效率与模式并存下该何去何从.

页: [1] 2

Powered by Discuz! Archiver 6.1.0  © 2001-2007 Comsenz Inc.