1、为什么可以直接使用 Route::get 调用呢? 因为这个是执行的 facade门面模式,就不具体说了,接下来看具体代码的流程
Route::get('hello/:name', 'index/hello');
2、定位到 get 方法,第一个参数是路由规则,第二个是路由地址等等,发现最后都是定位到了 rule 方法,
/**
* 注册GET路由
* @access public
* @param string $rule 路由规则
* @param mixed $route 路由地址
* @param array $option 路由参数
* @param array $pattern 变量规则
* @return RuleItem
*/
public function get($rule, $route = '', array $option = [], array $pattern = [])
{
return $this->rule($rule, $route, 'GET', $option, $pattern);
}
3、rule 方法中的 $this->group 是如何获取的?
/**
* 注册路由规则
* @access public
* @param string $rule 路由规则
* @param mixed $route 路由地址
* @param string $method 请求类型
* @param array $option 路由参数
* @param array $pattern 变量规则
* @return RuleItem
*/
public function rule($rule, $route, $method = '*', array $option = [], array $pattern = [])
{
return $this->group->addRule($rule, $route, $method, $option, $pattern);
}
我们会发现在 __construct 中有 setDefaultDomain() 方法,里面有一段 new domain 类,而 Domain 继承了 RuleGroup 类,这样就实例化了 RuleGroup 类,那么定位到 RuleGroup 中的 addRule 方法,如下图
/**
* 初始化默认域名
* @access protected
* @return void
*/
protected function setDefaultDomain()
{
// 默认域名
$this->domain = $this->host;
// 注册默认域名
$domain = new Domain($this, $this->host);
$this->domains[$this->host] = $domain;
// 默认分组
$this->group = $domain;
}
4、分析 addRule 方法
1、 首页自动完整匹配,当 $rule == / 或者为空时 $rule = $
2、创建路由规则实例,最后进行成员属性定义,走到 setRule 方法中。
3、 看到最后 rule 是否为 $,如果是的话,那么 去除 $, 并对 option['complete_match'] 赋值为 true
if ('$' == substr($rule, -1, 1)) {
// 是否完整匹配
$rule = substr($rule, 0, -1);
$this->option['complete_match'] = true;
}
4、去除左边的 / 符号
$rule = '/' != $rule ? ltrim($rule, '/') : '';
5、对 rule 中 有 : 号的 进行 转化。
if (false !== strpos($rule, ':')) {
$this->rule = preg_replace(['/\[\:(\w+)\]/', '/\:(\w+)/'], ['<\1?>', '<\1>'], $rule);
s} else {
$this->rule = $rule;
}
比如:rule 为 hello/:name 那么会转化为 hello/
比如: rule 为 hello/[:name] 那么会转化为 hello/
6、生成路由标识的快捷访问
1、分析路由规则中的变量,执行 parseVar 方法,当 rule 中存在 ?号,会 name => 2,否则为 1,
/**
* 分析路由规则中的变量
* @access protected
* @param string $rule 路由规则
* @return array
*/
protected function parseVar($rule)
{
// 提取路由规则中的变量
$var = [];
if (preg_match_all('/<\w+\??>/', $rule, $matches)) {
foreach ($matches[0] as $name) {
$optional = false;
if (strpos($name, '?')) {
$name = substr($name, 1, -2);
$optional = true;
} else {
$name = substr($name, 1, -1);
}
$var[$name] = $optional ? 2 : 1;
}
}
return $var;
}
array(1) {
["name"] => int(2)
}
array(1) {
["name"] => int(1)
}
2、生成 变量 $value
$value = [$this->rule, $vars, $this->parent->getDomain(), $suffix, $this->method];
array(5) {
[0] => string(13) "hello/"
[1] => array(1) {
["name"] => int(2)
}
[2] => string(9) "localhost"
[3] => NULL
[4] => string(3) "get"
}
3、通过容器中 rule_name 类 执行 set 方法,将解析的变量放入到 $this->item 属性中,
/**
* 注册路由标识
* @access public
* @param string $name 路由标识
* @param array $value 路由规则
* @param bool $first 是否置顶
* @return void
*/
public function set($name, $value, $first = false)
{
if ($first && isset($this->item[$name])) {
array_unshift($this->item[$name], $value);
} else {
$this->item[$name][] = $value;
}
}
4、注册路由规则, 生成对应类型的变量。
/**
* 注册路由规则
* @access public
* @param string $rule 路由规则
* @param RuleItem $route 路由
* @return void
*/
public function setRule($rule, $route)
{
$this->rule[$route->getDomain()][$rule][$route->getMethod()] = $route;
}
array(1) {
["localhost"] => array(1) {
["api"] => array(1) {
["get"] => object(think\route\RuleItem)#9 (10) {
["hasSetRule"] => NULL
["name"] => NULL
["rule"] => string(3) "api"
["method"] => string(3) "get"
["vars"] => array(0) {
}
["option"] => array(0) {
}
["pattern"] => array(0) {
}
["mergeOptions"] => array(6) {
[0] => string(5) "after"
[1] => string(5) "model"
[2] => string(6) "header"
[3] => string(8) "response"
[4] => string(6) "append"
[5] => string(10) "middleware"
}
["doAfter"] => NULL
["lockOption"] => bool(false)
}
}
}
}
7、最后在定位到 RouteGroup 方法,执行 $this->RuleItem,并返回RouteItem 实列对象
$this->addRuleItem($ruleItem, $method);
return $ruleItem;
public function addRuleItem($rule, $method = '*')
{
if (strpos($method, '|')) {
$rule->method($method);
$method = '*';
}
$this->rules[$method][] = $rule;
return $this;
}
array(8) {
["*"] => array(0) {
}
["get"] => array(1) {
[0] => object(think\route\RuleItem)#9 (10) {
["hasSetRule"] => bool(true)
["name"] => NULL
["rule"] => string(3) "api"
["method"] => string(3) "get"
["vars"] => array(0) {
}
["option"] => array(0) {
}
["pattern"] => array(0) {
}
["mergeOptions"] => array(6) {
[0] => string(5) "after"
[1] => string(5) "model"
[2] => string(6) "header"
[3] => string(8) "response"
[4] => string(6) "append"
[5] => string(10) "middleware"
}
["doAfter"] => NULL
["lockOption"] => bool(false)
}
}
["post"] => array(0) {
}
["put"] => array(0) {
}
["patch"] => array(0) {
}
["delete"] => array(0) {
}
["head"] => array(0) {
}
["options"] => array(0) {
}
}