php路由分发,Yaf Loader自动加载策略及Dispatcher路由分发策略

I mean

虽然鸟哥的文档已经介绍了,但是在实际应用中,我们总是会有一些特殊,而且根据鸟哥的文档,无法推理得知,必须从源码得知,故下面的内容基本上从源码中取得。

Yaf/Loader自动加载

Yaf/Loader相关的几个配置

PHP运行时配置

1

2

3

yaf.use_namespace 开启命名空间

yaf.use_spl_autoload 开启之后,可由PHP的自动加载函数加载,关闭是为了高效,Yaf只加载一次。

yaf.library 全局类库目录路径

Yaf应用配置

1

2

3

application.library 本地类库目录路径

application.library.directory 本地类库目录路径

application.library.namespace 以逗号分隔的本地库命名空间前缀

Yaf/Loader自动加载策略

1)如果未配置yaf.library和application.library时,Yaf_Loader::$_library及Yaf_Loader::$_global_library都将设置为[application.directory]/library;故不管是否配置application.library.namespace或者Yaf/Loader::registerLocalNamespace()是否注册本地命名空间前缀,加载类文件时,自动到[application.directory]/library目录查找类并加载。

2)如果配置了application.library时,但未配置application.library.namespace时或者未通过Yaf/Loader::registerLocalNamespace()注册本地命名空间前缀,不管yaf.library是否配置都到yaf.library中加载相应类文件。

3)如果配置了application.library和application.library.namespace,且类名中包含配置的命名空间前缀,则到application.library加载相应的类文件,否则到yaf.library中加载相应类文件。

4)Yaf内部中加载文件时,类名中有”_”会转换为目录分隔符。

yaf_loader.c

1

int yaf_internal_autoload(char *file_name, uint name_len, char **directory TSRMLS_DC);

443-456行,可以看到:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

while (1) {

while(++q && *q != '_' && *q != '/0');

if (*q != '/0') {

seg_len = q - p;

seg = estrndup(p, seg_len);

smart_str_appendl(&buf, seg, seg_len);

efree(seg);

smart_str_appendc(&buf, DEFAULT_SLASH);

p = q + 1;

} else {

break;

}

}

完成了”_”转换为目录分隔符。

Yaf/Dispatcher路由分发

yaf_dispatcher.c

1

static inline void yaf_dispatcher_fix_default(yaf_dispatcher_t *dispatcher, yaf_request_t *request TSRMLS_DC);

260-274行,可以看到:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

q = p;

*q = toupper(*q);

while (*q != '/0') {

if (*q == '_'

#ifdef YAF_HAVE_NAMESPACE

|| *q == '//'

#endif

) {

if (*(q+1) != '/0') {

*(q+1) = toupper(*(q+1));

q++;

}

}

q++;

}

会将路由解析中的模块名、控制器名先转换为小写,然后将首字母大写,其中控制器名会将”_”,”/”后面的一个字符转换为大写(源码展示了控制器名的处理)。

另外,还需要明确的是yaf支持的六个hook中的routerShutdown触发是在yaf_dispatcher_fix_default之后,而每次路由结束都会调用yaf_dispatcher_fix_default,这意味着什么?下面介绍。

实际应用

基于上述源码的分析,我们可以做什么呢?

默认情况下controllers下面的controller类文件,只能是首字母大写,如:

application/Modules/Demo/controllers/Acastatjob.php

可能有些强迫症患者就想这般:

application/Modules/Demo/controllers/AcaStatJob.php

对不起,直接这样会提示,无法找到类application/Modules/Demo/controllers/Acastatjob.php文件

如何搞?我们要写一个插件,在routerShutdown做简单一个替换:

定义插件

1

2

3

4

5

6

7

8

9

10

11

12

13

use Yaf/Plugin_Abstract;

use Yaf/Request_Abstract;

use Yaf/Response_Abstract;

class RoutePlugin extends Plugin_Abstract

{

public function routerShutdown(Request_Abstract $request, Response_Abstract $response){

$controller = $request->getControllerName();

$controller = str_replace('_', '', $controller);

$request->setControllerName($controller);

}

}

注册插件

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

use Yaf/Bootstrap_Abstract;

use Yaf/Dispatcher;

class Bootstrap extends Bootstrap_Abstract

{

/**

* 注册插件

*

* @access public

* @param Yaf/Dispatcher $dispatcher

* @return void

*/

public function _initPlugin(Dispatcher $dispatcher)

{

$dispatcher->registerPlugin(new RoutePlugin ());

}

}

1

http://backend.phpboy.net/demo/aca_stat_job/write

我们来分析一下解析流程:

Yaf/Application::app()->bootstrap()->getDispatcher->dispatch();

1.在yaf_dispatcher_route中,完成路由解析,得到module=demo,controller=aca_stat_job,action=write

2.在yaf_dispatcher_fix_default中,通过其处理得到module=Demo,controller=Aca_Stat_Job,action=write

3.在2中完成之后,通过hook机制,Request_Abstract::getControllerName(),然后将下划线替换为空字符,并setControllerName,其结果为module=Demo,controller=AcaStatJob,action=write

4.在yaf_internal_autoload中完成自动加载类文件

application/Modules/Demo/controllers/AcaStatJob.php

5.执行writeAction

然后假如我们不写plugin会怎样?

1.在yaf_dispatcher_route中,完成路由解析,得到module=demo,controller=aca_stat_job,action=write

2.在yaf_dispatcher_fix_default中,通过其处理得到module=Demo,controller=Aca_Stat_Job,action=write

3.在yaf_internal_autoload中,将类名中的下划线替换为”/“

4.在yaf_internal_autoload中完成自动加载类文件

application/Modules/Demo/controllers/Aca/Stat/Job.php

加载失败。

虽然加载失败,却给出了我们一个信息,可以加载分级目录的controller,但是注意controllers下面的子目录首字母要大写。

最后还有强迫症患者说

这样的Url不雅观,想把”_”换成”/“,如:

那么,在默认路由下你就不要传递url参数了,也就是说demo/aca/stat/job/write全部当作路由参数,不是数据参数,将头尾分别当前模块名和动作名,中间为控制器名,在routerShutdown拼接一个控制器,如:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

use Yaf/Plugin_Abstract;

use Yaf/Request_Abstract;

use Yaf/Response_Abstract;

class RoutePlugin extends Plugin_Abstract

{

public function routerShutdown(Request_Abstract $request, Response_Abstract $response){

$controller = $request->getControllerName();

$controller .= ucfirst($request->getActionName());

$params = $request->getParams();

$length = count($params);

$action = '';

$i = 1;

foreach ($params as $key => $value) {

if ($length == $i) {

if (is_null($value)) {

$action = $key;

} else {

$controller .= ucfirst($key);

$action = $value;

}

} else {

$controller .= ucfirst($key).ucfirst($value);

}

$i++;

}

$request->setControllerName($controller);

$request->setActionName($action);

}

}

当然这是最蛋疼的用法 ,不是么?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值