一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

Yaf框架自动加载和路由分发的使用方法

时间:2022-06-25 00:56:29 编辑:袖梨 来源:一聚教程网

一、自动加载(YafLoader)
1.YafLoader相关的几个配置
PHP运行时配置
yaf.use_namespace 开启命名空间
yaf.use_spl_autoload 开启之后,可由PHP的自动加载函数加载,关闭是为了高效,Yaf只加载一次。
yaf.library 全局类库目录路径
Yaf应用配置
application.library 本地类库目录路径
application.library.directory 本地类库目录路径
application.library.namespace 以逗号分隔的本地库命名空间前缀
2.YafLoader自动加载策略
1)如果未配置yaf.library和application.library时,Yaf_Loader::$_library及Yaf_Loader::$_global_library都将设置为[application.directory]/library;故不管是否配置application.library.namespace或者YafLoader::registerLocalNamespace()是否注册本地命名空间前缀,加载类文件时,自动到[application.directory]/library目录查找类并加载。
2)如果配置了application.library时,但未配置application.library.namespace时或者未通过YafLoader::registerLocalNamespace()注册本地命名空间前缀,不管yaf.library是否配置都到yaf.library中加载相应类文件。
3)如果配置了application.library和application.library.namespace,且类名中包含配置的命名空间前缀,则到application.library加载相应的类文件,否则到yaf.library中加载相应类文件。
4)Yaf内部中加载文件时,类名中有"_"会转换为目录分隔符。
yaf_loader.c


int yaf_internal_autoload(char *file_name, uint name_len, char **directory TSRMLS_DC);
443-456行,可以看到:

 代码如下 复制代码

while (1) {
     while(++q && *q != '_' && *q != '');


     if (*q != '') {
          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;
     }
}

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

2.路由分发(YafDispatcher)
yaf_dispatcher.c


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

260-274行,可以看到:

 代码如下 复制代码
q = p;
*q = toupper(*q);
while (*q != '') {
     if (*q == '_'
#ifdef YAF_HAVE_NAMESPACE
               || *q == ''
#endif
        ) {
          if (*(q+1) != '') {
               *(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做简单一个替换:
定义插件

 代码如下 复制代码

use YafPlugin_Abstract;
use YafRequest_Abstract;
use YafResponse_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);
     }
}

注册插件

 代码如下 复制代码


use YafBootstrap_Abstract;
use YafDispatcher;


class Bootstrap extends Bootstrap_Abstract
{


    /**
     * 注册插件
     *
     * @access public
     * @param YafDispatcher $dispatcher
     * @return void
     */
    public function _initPlugin(Dispatcher $dispatcher)
    {
        $dispatcher->registerPlugin(new RoutePlugin ());
    }
}

我们来分析一下解析流程:
YafApplication::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参数了,也就是说demo/aca/stat/job/write全部当作路由参数,不是数据参数,将头尾分别当前模块名和动作名,中间为控制器名,在routerShutdown拼接一个控制器,如:

 代码如下 复制代码

use YafPlugin_Abstract;
use YafRequest_Abstract;
use YafResponse_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);
    }
}

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

热门栏目