URL路由
路由功能也是一个很重要的功能点,需要和大家一起学习一下,其实在之前的项目中,我很少会用到它,因为,通过常规的访问方式就已经很方便了,再其次,CI的框架目录已经非常简单了,所以默认的路由用起来完全可以了。但这里,我希望和大家一起看下CI的路由实现原理,首先,我们先写个例子,让程序 run 起来,然后再看源代码。
首先,我在 application/config/routes.php 定义了一些路由,并且新建了对应的控制器及方法:
/**
* 自定义的路由
*/
// 使用通配符
$route['product/(:num)'] = 'catalog/product_lookup/$1';
// restful 风格
$route['rest/(\d+)']['get'] = 'api/get/$1';
// restful 风格
$route['rest/(\d+)']['delete'] = 'api/delete/$1';
// 回调方式
$route['product/([a-zA-Z]+)/edit/(\d+)'] = function ($product_type, $id)
{
return 'catalog/product_edit/' . strtolower($product_type) . '/' . $id;
};
// 登录成功后,回到原先界面
$route['login/(.+)'] = 'auth/login/$1';
第一个路由控制器及方式代码示例:
class Catalog extends CI_Controller {
/**
* Catalog Page for this controller.
*/
public function product_lookup($id)
{
print_r($id);
}
public function product_edit($product_type, $id)
{
print_r($product_type);
}
}
当我们访问 http://localhost:8100/product/31 时,URL路由会触发 第一条路由,返回 product_id:
好啦,代码已经成功 run 起来了,我们现在去揭开 URL路由 的面纱,去搜寻他的本质:
/*
1. ------------------------------------------------------
2. Instantiate the URI class
3. ------------------------------------------------------
*/
# 在 CodeIgniter.php 文件304行,CI 加载了 URL 类
$URI =& load_class('URI', 'core');
/*
4. ------------------------------------------------------
5. Instantiate the routing class and set the routing
6. ------------------------------------------------------
*/
# 加载路由类
$RTR =& load_class('Router', 'core', isset($routing) ? $routing : NULL);
好,我们接下来进入到 URI 类中,看看他到底做了哪些事:
# URI 的构造函数
public function __construct()
{
# 加载配置核心类
$this->config =& load_class('Config', 'core');
// If query strings are enabled, we don't need to parse any segments.
// However, they don't make sense under CLI.
# is_cli() 是检测 CI 的运行环境(fast-cgi[浏览器访问] 和 cli[控制台])
# enable_query_strings 在 application/config.php 默认为 FALSE
if (is_cli() OR $this->config->item('enable_query_strings') !== TRUE)
{
# 被允许的 url 字符
# 在 application/config.php 中定义(a-z 0-9~%.:_\-)
$this->_permitted_uri_chars = $this->config->item('permitted_uri_chars');
// If it's a CLI request, ignore the configuration
# 如果是 cli 环境
# 有很多人会疑问,到底 cli 环境怎么去访问 web
# 我在文章结尾处会给大家演示
# 心急的可以直接去看看,不急的可以先看完这些源码 ^_^
if (is_cli())
{
# 调用 _parse_argv,赶紧去看看(如下)
# 这里得到的 $uri 类似等于 welcome/index 形式
$uri = $this->_parse_argv();
}
else
{
# 非 cli 环境
# 协议,application/config.php 文件中定义了 REQUEST_URI
$protocol = $this->config->item('uri_protocol');
# 初始化
empty($protocol) && $protocol = 'REQUEST_URI';
switch ($protocol)
{
case 'AUTO': // For BC purposes only
case 'REQUEST_URI':
# go go go !!! go to _parse_request_uri()
$uri = $this->_parse_request_uri();
break;
case 'QUERY_STRING':
$uri = $this->_parse_query_string();
break;
case 'PATH_INFO':
default:
$uri = isset($_SERVER[$protocol])
? $_SERVER[$protocol]
: $this->_parse_request_uri();
break;
}
}
# go to _set_uri_string($uri)
$this->_set_uri_string($uri);
}
log_message('info', 'URI Class Initialized');
}
_parse_argv() 方法:
/**
7. Parse CLI arguments
8. 9. Take each command line argument and assume it is a URI segment.
10. 11. @return string
*/
protected function _parse_argv(